> Sorry. I was replying through my cellphone and didn't read your code
> properly. I didn't notice the reassignment of 'f' to 'r'. But considering
> that r is the object being cleaned up, wouldn't it make more sense to move
> defer right below r?
Putting the deferred close right next to the open, as Nigel did, makes
the code obviously correct. Having the defer up at the declaration of
r does not. And if you go to edit the code, you are likely to make the
correct modifications, particularly if the function is long. Locality
matters, particularly for humans.
> In addition, calling a function has a cost. The cost may be small by today's standard, but when you put this inside a long loop, it may become significant, unless if Go compiler is smart enough to know which of these functions should be inlined.
The compiler does not currently inline any functions at all that
include a defer. However, if you consider what is required for
correctness--including having the correct state of memory and local
variables, having the correct tracebacks, running multiple defers,
etc.--I think you would find that any correct implementation of defer
will not be made much cheaper by avoiding the function call overhead.
Another consideration:
Using function scoping for defers is general. You can get any behavior
you want using a closure. However, some scopes are not accessible in
the way you might want for your proposal. For example, consider:
func f() {
// ...
func() {
for i := 0; i < 3; i++ {
x := use(i)
defer cleanup(x)
}
}()
// ...
}
This will clean up everything once the entire for loop completes. The
relevant scope is the entire for loop (the scope at which i is
declared). However, the scope of each call to defer is the scope of
the body of the for loop (the scope at which x is declared). There is
simply nowhere in the body of a for loop to put a defer that executes
at the scope of the entire loop--and yet the calls you want to make to
defer may depend on values calculated in the body of the loop.
-josh