Join Nostr
2026-10-11 09:23:15 UTC
in reply to

wicked witch of the unix on Nostr: i don't see how that constrains anything? deferred blocks would be called on ...

i don't see how that constrains anything? deferred blocks would be called on basically the same order as c++ destructors, plus you can defer whole blocks if you need more at cleanup time

and i take

```c
type *foo = make_foo();
defer free_foo(foo);
// ...;
if ((err = some_call()))
return err;
type *nya = make_nya(&foo);
defer free_nya(nya);

if ((err = some_other_call()))
return err;
//...;
```

over

```c
type *foo = make_foo();
// ...;
if ((err = some_call()))
goto cleanup_foo;
// ...;
type *nya = make_nya(&foo);

if ((err = some_other_call()))
goto cleanup_nya;
// ...;
cleanup_nya:
free_nya(nya);
cleanup_foo:
free_foo(foo);
return err;
```

for the defer example, i see foo, i see deferring it's cleanup, i don't think about foo's resources on exit anymore

on the goto example, i constantly have to think about it, if i change some calls around i gotta double check which labels it's jumping to, it's a lot easier to make a mistake refactoring and get a double-free or leak

and to me, defer is not any less explicit, for the goto example if i'm looking at the cleanup at the end i have to be aware of every single point in the function that jumps to it, i have to personally keep track of allocation order to make sure cleanup order is correct (nya takes a foo, so foo *has* to be cleaned up later)

defer just handles all that by design, all i have to do is keep the defer close to the allocation and now i don't have to worry much about ordering on the 99% of common cases; it's still explicit, it's still there in the function telling me the flow, it's not like destructors living in another file completely and being called implicitly

(and sure defer isn't idea on every case, it's made to avoid common mistakes, just like we have `for (init; cond; end) body;` loops instead of `init; again: if (cond) goto over; body; end; goto again; over:`)