Live data from Hacker News

A Defer Mechanism for C

gustedt.wordpress.com

41–50 of 248 posts

Re: A Defer Mechanism for C

#41

I’ve always considered “defer” an inelegant kludge in comparison to RAII for automatic cleanup of resources. It’s surprising that the C standards committee is considering adding that to the language. Then again, nearly none of the syntactic C features post-C89 have been very compelling or widely adopted.

Also defer runs even if your code panic which is great.

Re: A Defer Mechanism for C

#42

I’ve always considered “defer” an inelegant kludge in comparison to RAII for automatic cleanup of resources. It’s surprising that the C standards committee is considering adding that to the language. Then again, nearly none of the syntactic C features post-C89 have been very compelling or widely adopted.

Exactly. I always explain this but people tend to ignore and not see how error prone defer is. It is a shame that a kludge (ugly hack actually) like this receives so much praise.

Re: A Defer Mechanism for C

#43
post #2

Despite being convenient,I have the feeling that it might be a bad idea. One of the key interest of C compared to more recent languages is that everything is explicit. With a finger you can follow the code as it runs and know exactly what is going on and when exactly. At the opposite, there is c++ that does a lot of things automagically. And it is often hard to understand why you suddenly get a segfault out of blue,…

guard/defer is semantically and syntactically as explicit (or implicit) as C's automatic storage class (https://en.cppreference.com/w/c/language/storage_duration), which is the default storage class.

Re: A Defer Mechanism for C

#44
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.

Starting in page 16, there is a section called "Do we want a guard keyword?" that talks about this. They give an example showing that deferring to the end of the containing block is possible without the guard keyword, although it's a bit wonky, requiring to duplicate the "if". With guard keyword:

    guard {
        void *ptr = malloc(12);
        if (ptr) {
            defer free(ptr);
            // Use ptr
        }
        // Use ptr some more
    } // free ptr here
Without guard keyword:

    {
        void *ptr = malloc(12);
        defer { if (ptr) free(ptr); }
        if (ptr) {
            // Use ptr
        }
        // Use ptr some more
    } // free ptr here

Re: A Defer Mechanism for C

#45
post #13

I’ve always considered “defer” an inelegant kludge in comparison to RAII for automatic cleanup of resources. It’s surprising that the C standards committee is considering adding that to the language. Then again, nearly none of the syntactic C features post-C89 have been very compelling or widely adopted.

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).

I would strongly disagree on RAII being a kludge in C++. The language feature that enables it is deterministic destructors, whose primary purpose is to ensure that allocated resources are deallocated. RAII is one particular use of destructors. The primary goal is to have the object be the thing that owns a resource, not the calling scope.

In terms of usability, destructors allow for resource management that is far easier at the call site than any other language. "with" blocks such as in python require the call site to be modified to include the explicit time of destruction, whereas C++ gets that for free from its existing scoping rules. "try/finally" such as in Java also requires modifying the call site, but at least has reasonable default behavior if accidentally omitted. "defer" feels like it has the worst of both worlds. It requires the call site to be modified when a resource is owned, and also requires the caller to know what the corresponding cleanup function is for any allocation.

Re: A Defer Mechanism for C

#46
In its current form, this is really stupid, because of something like this:

    guard {
        for (int i = 0; i 
Now the compiler has to:

1. implement some side of capture/closure mechanism to keep all the 'i's to the end of the guard block

2. do dynamic allocation to store the closures so they can be executed at the end did the scope

1 seems like too much work for such a feature, and 2 is a massive no. Implicit dynamic allocation, in C?

And all of this for nothing. The guard syntax doesn't give any reasonable benefits. They should have just kept it simple; defer happens at the end of the scope, and it just takes 'i' by "reference". It's a shame because it's a feature I would really like to have.

Re: A Defer Mechanism for C

#47
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.

It shouldn't be. std::unique_ptr is very clear.

(std::shared_ptr should be used only when absolutely required and should be kept under close watch the whole time.)

Re: A Defer Mechanism for C

#48
post #2

Despite being convenient,I have the feeling that it might be a bad idea. One of the key interest of C compared to more recent languages is that everything is explicit. With a finger you can follow the code as it runs and know exactly what is going on and when exactly. At the opposite, there is c++ that does a lot of things automagically. And it is often hard to understand why you suddenly get a segfault out of blue,…

Despite being convenient,I have the feeling that it might be a bad idea.

What is "I am thinking of using C?"

Re: A Defer Mechanism for C

#49

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…

It would be easier to execute the argument expressions immediately, as golang does.

If they add this, it would be better to restrict it to the current scope, to avoid forcing the language to create complexity to handle defers created via loop in the background.

Of course, that leads to the question of what to do when you loop over a defer with a goto, which would make sense if you were constantly appending function pointers and arguments to the frame similar to alloca.

That could lead to fun things like a function getting inlined into a for loop and then having its defers that would have been in function instead piled together to blow the stack.

They'll have to make sure they account for that in the spec and implementations.

Mostly, it would be easier to remember that C should not be using such a pattern, and that if you have need of defers and various similar magic to be baked into the language and compiler, what you're doing is probably inappropriate for implementation in the C language in the first place.

Re: A Defer Mechanism for C

#50

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 {}…

I agree.

Dlang already has scope guards (Appendix C in the OP) https://dlang.org/spec/statement.html#scope-guard-statement, and does so at block scope. For some code it's a more elegant solution (keeps acquire and release code close together), without introducing the usual C++ RAII issues.

Post reply on HN