3 ms·
Ugh. Go's "defer" is reasonably clean because Go is garbage-collected. So you don't have to worry about something being deleted before a queued "defer" runs. T
by Animats 2y ago
Ugh.
Go's "defer" is reasonably clean because Go is garbage-collected. So you don't have to worry about something being deleted before a queued "defer" runs. That's well-behaved. This is going to be full of ugly, non-obvious problems.
Interestingly, it's not really "defer" in the Go sense. It's "finally", in the try/finally sense of C++, using Go-type "defer" syntax". This mostly matters for scope and ownership issues. If you want to close a file in a defer, and the file is a local variable, you have to be sure that the close precedes the end of block de-allocation. Most of the discussion in the article revolves around how to make such problems behave halfway decently.
"defer" happens invisibly, in the background. That's contrary to the basic simplicity of C, where almost nothing happens invisibly.
- codr7 2y agoThe point of defer is to put the cleanup logic in one place for local variables though, so the risk of someone else deleting it isn't a thing.
- deleted 2y ago[deleted]
- jayd16 2y ago> It's "finally", in the try/finally sense of C++ What sense is that? C++ doesn't have finally and the article explicitly calls out how its not like destructors.
- Animats 2y agoRight, C++ doesn't have "finally". But "defer" defers to when a "finally" section would run in a language that has it. I think.
- IshKebab 2y agoThat's what it does in Go too. This is totally defer in the Go sense (except they fixed the scoping issue).
- Animats 2y agoNot quite. "The central idea behind defer is that, unlike its Go counterpart, defer in C is lexically bound, or “translation-time” only, or “statically scoped”" Defer in Go puts the deferred action on a run time to-do list that's processed at function exit. You can queue up deferred actions from a loop in Go. Not in this proposal for C. What happens in this C proposal if you put a defer request inside a loop? Is it a compile time error, do they somehow to try to give it meaningful semantics, or is it undefined behavior?
- deleted 2y ago[deleted]
- deleted 2y ago[deleted]
- gizmo686 2y agoLoops in C introduce a new lexical scope, so the defer runs once for every loop iteration. Assuming you are using defer for destructor purposes, and use it where you declare your variable, this would generally be what you want, as it frees the memory at the same time it goes out of scope. The flip side of this is that code like the following would be broken: char *foo = NULL; if (true) { foo = calloc(1,1); defer { free(foo); } } char c = *foo; As foo gets freed at the end of the conditional, which is prior to the dereference.
- IshKebab 2y agoThat particular example is easy - just put the defer before the if.
- sethaurus 2y ago> What happens in this C proposal if you put a defer request inside a loop? Is it a compile time error, do they somehow to try to give it meaningful semantics, or is it undefined behavior? The action runs at the end of the loop-body, before the next iteration. It does this because the loop-body is the enclosing block, and a defer will always run when its enclosing block ends. As described in the article, this is intentionally-so and makes it possible to acquire a mutex inside a loop while automatically releasing it before the next iteration, something which is easy to get wrong in Go.