Live data from Hacker News

A Defer Mechanism for C

gustedt.wordpress.com

31–40 of 248 posts

Re: A Defer Mechanism for C

#31

The best way to think about defer is that all the deferred statements are put in a goto label at the end of the block. When you break/return/whatever, it just jumps to that label first. This just makes slightly more convenient what the standard approach to error handling in C systems programming already is. Looking at the article, this specific implementation doesn’t quite go all the way, requiring a special guard {}…

How can you get away from having an explicit guard block?

Without one, you couldn't 'defer' to the end of a containing block from within an if/while/do/for/etc. block.

When/where the deferred code is executed has to be specified some way so an explicit marker for the defer 'scope' is surely required without severely limiting the utility of the feature.

Re: A Defer Mechanism for C

#32
post #18

Earlier quoted context omitted.

> Or you know... free the things you need to free and move on with your life And leave memory leaks, buffer overflows, and bugs in the process, and we've done for the past 40+ years...

Sure. But defer just changes the problem from forgetting to write free to forgetting to write defer. So we’re not really talking about provably correct solutions... just things that can work. And I think a context or just manually freeing can work nicely.

>Sure. But defer just changes the problem from forgetting to write free to forgetting to write defer.

Yes, which is a much better formulation.

Re: A Defer Mechanism for C

#33
post #20

Earlier quoted context omitted.

The whole point is that it's much easier to NOT forget defer (which goes right after the resource acquisition line), than to forget to free the resource (which happens much further down the function). So it's immediately better compared to the current C situation. As for compared to RAII? Well, thats one failure mode for defer (forgetting it), whereas there are dozens of ways to mess RAII...

I made no comparison between “defer” and the current C situation. In comparison to RAII, “defer” as a language feature is a kludge. Mainly because RAII completely solves the problem of correct resource cleanup for API users while “defer” does not.

RAII is an idiom, not a language feature. Destructors might be the language feature, but they have their own issues and caveats.

So I don't see the comparison...

Re: A Defer Mechanism for C

#34
Re: Should object values be captured?

The results from 387 responses (to a Twitter poll) show a 2:1 preference for the value being read at the time the deferred statements are executed (66.9%) rather than when the defer statement encountered(33.1%).

Since both options - by value and by reference - may be viewed as reasonable or desirable, neither should be a default. Instead, they both should be using a special syntax. So if you write something likes this -

  guard {
    void * p = malloc(...);
    defer free(p);
  }
it simply won't compile. Instead you'd need to say something like this -

  guard {
    void * p = malloc(...);
    defer free(^p); // evaluate now
  }

  guard {
    void * p = malloc(...);
    defer free(p^); // evaluate later
  }
This may also be reused later for specifying lambda captures... should lambdas ever make their way into C.

Re: A Defer Mechanism for C

#35
post #23
post #6

Earlier quoted context omitted.

> One of the key interest of C compared to more recent languages is that everything is explicit. There's nothing implicit about defer.

Deferred actions are not explicit at the exit points. That's quite implicit. You can no longer reason about a local piece of code; you now have to know its lexical nesting up to top level to see if it's inside a guard block that might trigger hidden behavior.

That's still local at the scope level though, which is quite acceptable.

Plus, to handle the free or the leak if you had forgotten to free a resource at the exit point would also require to "know its lexical nesting up to top level".

Between goto and longjump and co, C has much worse non-local behavior than defer.

Re: A Defer Mechanism for C

#36
post #31

The best way to think about defer is that all the deferred statements are put in a goto label at the end of the block. When you break/return/whatever, it just jumps to that label first. This just makes slightly more convenient what the standard approach to error handling in C systems programming already is. Looking at the article, this specific implementation doesn’t quite go all the way, requiring a special guard {}…

How can you get away from having an explicit guard block? Without one, you couldn't 'defer' to the end of a containing block from within an if/while/do/for/etc. block. When/where the deferred code is executed has to be specified some way so an explicit marker for the defer 'scope' is surely required without severely limiting the utility of the feature.

You would just follow the C variable scope rules I think. But I see now how this creates an issue if you want to put the defer, but not the acquisition of the resource it releases, within a control statement.

Re: A Defer Mechanism for C

#37
post #13

Earlier quoted context omitted.

defer is great for many use cases, available in Go, Swift and other languages, and nothing like a kludge. If anything RAII is unfit for C (which doesn't have classes), and in itself, a kludge (it's an idiom, not a language feature).

What if you forget to call “defer”? Then your code is incorrect. That’s kludgy in comparison to RAII where it’s impossible to forget to call a destructor.

Non-obvious need to call defer was what made me stop trying out Go. When I was making HTTP requests there was no Close() method on the response so it seemed like it wasn't needed. But later I found out that there is a Close() method on the response's Body member that needs to be called (only one code sample in the docs even showed that).

RAII is the best for ensuring that things get cleaned up even if it does lead to more boilerplate to add the pattern to things. But even .NET's IDisposable feels better than defer. It's established practice to implement it if your class contains something that must be disposed. And it's easy for tools to check if you haven't disposed of something that implements IDisposable.

All that said, I find defer to be better than nothing. In C, the best I can do for cleanup is having all the cleanup functions called at the end with labels at the various points I need to jump to.

Re: A Defer Mechanism for C

#38
post #9

Earlier quoted context omitted.

Destructors are not called randomly.

"Smart pointers go brr" It's not really random, but it's quite hard to follow.

That's really an argument against smart (to be precise, shared) pointers, not against destructors.

Re: A Defer Mechanism for C

#39
post #9

Earlier quoted context omitted.

Destructors are not called randomly.

"Smart pointers go brr" It's not really random, but it's quite hard to follow.

If it's too cold for you, it's too cold for your smart pointers. Bring your smart pointers inside during the winter months.

Re: A Defer Mechanism for C

#40

Re: Should object values be captured? The results from 387 responses (to a Twitter poll) show a 2:1 preference for the value being read at the time the deferred statements are executed (66.9%) rather than when the defer statement encountered(33.1%). Since both options - by value and by reference - may be viewed as reasonable or desirable, neither should be a default. Instead, they both should be using a special synta…

The ^ is already taken in context of "C lambdas" though (hoping that if C ever gets lambdas it will simply adopt clang blocks instead of a C++ like syntax):

https://clang.llvm.org/docs/BlockLanguageSpec.html

Post reply on HN