That is a different approach, but I don't think you've demonstrated why it's better. Seems like that approach forces you to introduce a new scope for every resource, which might otherwise be unnecessary:
using (var resource1 = acquire() {
using (var resource2 = acquire()) {
using (var resource3 = acquire()) {
// use resources here..
}
}
}
Compared to: var resource1 = acquire();
defer { release(resource1); }
var resource2 = acquire();
defer { release(resource2); }
var resource3 = acquire();
defer { release(resource3); }
// use resources here
Of course if you want the extra scopes (for whatever reason), you can still do that with defer, you're just not forced to.
While the macro version doesn't permit this, if it were built-in syntax (as in C#) we can write something like:
The argument for this approach is it is structural. `defer` statements are not structural control flow: They're `goto` or `comefrom` in disguise.---
Even if we didn't want to introduce new scope, we could have something like F#'s `use`[1], which makes the resource available until the end of the scope it was introduced.
In either case (using or use-defer), the acquisition and release are coupled together in the code. With `defer` statements they're scattered as separate statements. The main argument for `defer` is to keep the acquisition and release of resources together in code, but defer statements fail at doing that.[1]:https://learn.microsoft.com/en-us/dotnet/fsharp/language-ref...