Live data from Hacker News

Defer available in gcc and clang

gustedt.wordpress.com

151–160 of 262 posts

Re: Defer available in gcc and clang

#151
post #108

The article is a bit dense, but what it's announcing is effectively golang's `defer` (with extra braces) or a limited form of C++'s RAII (with much less boilerplate). Both RAII and `defer` have proven to be highly useful in real-world code. This seems like a good addition to the C language that I hope makes it into the standard.

To be fair, RAII is so much more than just automatic cleanup. It's a shame how misunderstood this idea has become over the years

Can you share some sources that give a more complete overview of it?

I got out my 4e Stroustrup book and checked the index, RAII only comes up when discussing resource management.

Interestingly, the verbatim introduction to RAII given is:

> ... RAII allows us to eliminate "naked new operations," that is, to avoid allocations in general code and keep them buried inside the implementation of well-behaved abstractions. Similarly "naked delete" operations should be avoided. Avoiding naked new and naked delete makes code far less error-prone and far easier to keep free of resource leaks

From the embedded standpoint, and after working with Zig a bit, I'm not convinced about that last line. Hiding heap allocations seems like it make it harder to avoid resource leaks!

Re: Defer available in gcc and clang

#152
post #44

Earlier quoted context omitted.

>we both agree it's really a good move Actually I am not sure I do. It seems to me that even though `defer` is more explicit than destructors, it still falls under "spooky action at a distance" category.

I don't understand why destructors enter the discussion. This is C, there is no destructors. Are you comparing "adding destructors to C" vs "adding defer to C"? The former would be bring so much in C that it wouldn't be C anymore. And if your point is "you should switch to C++ to get destructors", then it seems out of topic. By very definition, if we're talking about language X and your answer is "switch to Y", this…

Sorry, I had some other thread that involved destructors in my head.

But the point is `defer` is still in "spooky action at a distance" category that I generally don't want in programming languages, especially in c.

Re: Defer available in gcc and clang

#153
post #107
post #104

Earlier quoted context omitted.

The go way of dealing with it is wrapping the block with your defers in a lambda. Looks weird at first, but you can get used to it.

I know. Or in some cases, you can put the loop body in a dedicated function. There are workarounds. It's just bad that the wrong way a) is the most obvious way, and b) is silently wrong in such a way that it appears to work during testing, often becoming a problem only when confronted with real-world data, and often surfacing only as being a hard-to-debug performance or resource usage issue.

[deleted]

Re: Defer available in gcc and clang

#154
post #150
post #83

Earlier quoted context omitted.

I don't think so. As a contributor to GCC, I also wished it hadn't.

Why do you think so?

For two reasons: First, where C++ features are used, it make the code harder to understand rather than easier. Second, it requires newer and more complex toolchains to build GCC itself. Some people still maintain the last C version of GCC just to keep the bootstrap path open.

Re: Defer available in gcc and clang

#155
post #124
post #118

Earlier quoted context omitted.

>"this is how the resource is acquired, this is how the resource will be freed later" Lovely fairy tale. Now can you tell me how you love to scroll back and examine all the defer blocks within a scope when it ends to understand what happens at that point?

I don't typically do that. In 99.999% of cases, 'defer free(something)' was done because it's the correct thing to do at every exit point, so I don't need to think about it at the end of the block.

If you only ever work in your own code bases, sure.

Re: Defer available in gcc and clang

#156
post #5

Earlier quoted context omitted.

Probably closer to defer in Zig than in Go, I would imagine. Defer in Go executes when the function deferred within returns; defer in Zig executes when the scope deferred within exits.

I would like to second this. In Golang if you iterate over a thousand files and defer File.close() your OS will run out of file descriptors

Well, unless you're on Windows :D Even on Windows XP Home Edition I could open a million file handles with no problems.

Seriously, why is default ulimit on file descriptors on Linux measly 1024?

Re: Defer available in gcc and clang

#157
post #43

The article is a bit dense, but what it's announcing is effectively golang's `defer` (with extra braces) or a limited form of C++'s RAII (with much less boilerplate). Both RAII and `defer` have proven to be highly useful in real-world code. This seems like a good addition to the C language that I hope makes it into the standard.

Both defer and RAII have proven to be useful, but RAII has also proven to be quite harmful in cases, in the limit introducing a lot of hidden control flow. I think that defer is actually limited in ways that are good - I don't see it introducing surprising control flow in the same way.

Defer is also hidden control flow. At the end of every block, you need to read backwards in the entire block to see if a defer was declared in order to determine where control will jump to. Please stop pretending that defer isn't hidden control flow.

> RAII has also proven to be quite harmful in cases

The downsides of defer are much worse than the "downsides" of RAII. Defer is manual and error-prone, something that you have to remember to do every single time.

Re: Defer available in gcc and clang

#158
post #111

In C I just used goto - you put a cleanup section at the bottom of your code and your error handling just jumps to it. #define RETURN(x) result=x;goto CLEANUP void myfunc() { int result=0; if (commserror()) { RETURN(0); } ..... /* On success */ RETURN(1); CLEANUP: if (myStruct) { free(myStruct); } ... return result } The advantage being that you never have to remember which things are to be freed at which particular…

The disadvantage is that a "goto fail" can easily happen with this approach. And it actually had happened in the wild.

Re: Defer available in gcc and clang

#159
post #142

Earlier quoted context omitted.

C in C++ is a pretty terrible experience. The differences your asterisk alludes to are actually quite significant in practice: C++ doesn't let you implicitly cast from void* to other pointer types. This breaks the way you typically heap-allocate variables in C: instead of 'mytype *foo = malloc(sizeof(*foo))', you have to write 'mytype *foo = (mytype *)malloc(sizeof(*foo))'. This adds a non-trivial amount of friction…

I'll give you the last bullet you missed, you're also giving up the { [3] = ..., [5] = ... } array initializer syntax. I like both these syntax-es (syntacies? synticies?) and I hope they make their way to C++, but if we're honestly evaluating features -- take their utility, multiply it by 100 and in my book it's still losing out against either defer or slices/span types. If you disagree with this, then your calculus…

I write way more C++ than I write C. I was not comparing C and C++ in terms of which language is better or has more significant features. I was evaluating your suggestion to write C in C++ and get defer that way.

Re: Defer available in gcc and clang

#160
post #111

In C I just used goto - you put a cleanup section at the bottom of your code and your error handling just jumps to it. #define RETURN(x) result=x;goto CLEANUP void myfunc() { int result=0; if (commserror()) { RETURN(0); } ..... /* On success */ RETURN(1); CLEANUP: if (myStruct) { free(myStruct); } ... return result } The advantage being that you never have to remember which things are to be freed at which particular…

This looks like a recipe for disaster when you'll free something in the return path that shouldn't be freed because it's part of the function's result, or forget to free something in a success path. Just write result=x; goto cleanup; if you meant result=x; goto cleanup; At least then you'll be able to follow the control flow without remembering what the magic macro does.

In your cleanup method you have to take the same care of parameters that you are putting results into as any other way you can deal with this. All it does is save you from repeating such logic at all the exit points.
Post reply on HN