Live data from Hacker News

Defer available in gcc and clang

gustedt.wordpress.com

131–140 of 262 posts

Re: Defer available in gcc and clang

#131
post #7

It’s pedantic, but in the malloc example, I’d put the defer immediately after the assignment. This makes it very obvious that the defer/free goes along with the allocation. It would run regardless of if malloc succeeded or failed, but calling free on a NULL pointer is safe (defined to no-op in the C-spec).

Free works with NULL, but not all cleanup functions do. Instead of deciding whether to defer before or after the null check on a case-by-case basis based on whether the cleanup function handles NULL gracefully, I would just always do the defer after the null check regardless of which pair of allocation/cleanup functions I use.

Re: Defer available in gcc and clang

#132
post #58
post #29

Would defer be considered hidden control flow? I guess it’s not so hidden since it’s within the same function unlike destructors, exceptions, longjmp.

It's one of the most commonly adopted feature among C successor languages (D, Zig, Odin, C3, Hare, Jai); given how opinionated some of them are on these topics, I think it's safe to say it's generally well regarded in PL communities.

In Nim too, although, the author doesn't like it much.

Re: Defer available in gcc and clang

#134
post #78

I took some shit in the comments yesterday for suggesting "you can do it with a few lines of standard C++" to another similar thread, but yet again here we are. Defer takes 10 lines to implement in C++. [1] You don't have to wait 50 years for a committee to introduce basic convenience features, and you don't have to use non-portable extensions until they do (and in this case the __attribute__((cleanup)) has no equiva…

Why is this a relevant comment? We're talking about C, not C++. If you wanted to suggest using an alternative language, you're probably better off recommending Zig: defer takes 0 lines to implement there, and it's closer to C than what C++ is.

Everyone reading this (you included) knows full well that unlike Zig/Rust/Odin/whatever, C++ has the special property that you can quite literally* write C code in it, AND you can implement whatever quality of life fixes you need with targeted usage of RAII+templates+macros (defer, bounds checked accesses, result types, whatever).

My comment is targeted towards the programmer who is excited about features like this - you can add an extra two characters to your filename and trivially implement those improvements (and more) yourself, without any alterations to your codebase or day to day programming style.

Re: Defer available in gcc and clang

#135

Earlier quoted context omitted.

One small nitpick: you don't need check before `free` call, using `free(NULL)` is fine.

But it does keep one in the habit of using NULL checks.

It is pointless, because in Linux all you get is a virtual address. Physical backing is only allocated on first use.

In other words, the first time you access a "freshly allocated" non-null pointer you may get a page fault due to insufficient physical memory.

Re: Defer available in gcc and clang

#136
post #29

Would defer be considered hidden control flow? I guess it’s not so hidden since it’s within the same function unlike destructors, exceptions, longjmp.

It breaks the idea that statements get executed in the order they appear in the source code, but it ‘only’ moves and sometimes deduplicates (in functions with multiple exit points) statements, it doesn’t hide them.

Of course, that idea already isn’t correct in many languages; function arguments are evaluated before a function is called, operator precedence often breaks it, etc, but this moves entire statements, potentially by many lines.

Re: Defer available in gcc and clang

#137
post #62

As others have commented already: if you want to use C++, use C++. I suspect the majority of C programmers neither care nor want stuff like this; I still stay with C89 because I know it will be portable anywhere, and complexities like this are completely at odds with the reason to use C in the first place.

Then why not even better, K&R C with external assembler, that is top. /s

> external assembler

Is that supposed to exacerbate how poor that choice is. External assembly is great.

Re: Defer available in gcc and clang

#138
post #56

Earlier quoted context omitted.

This example is exactly why RAII is the solution to this problem and not defer.

defer is literally just an explicit RAII in this example. That is, it's just unnecessary boiler plate to wrap the newResource handle into a struct in this context. In addition, RAII has it's own complexities that need to be dealt with now, i.e. move semantics, which obviously C does not have nor will it likely ever.

> RAII has it's own complexities that need to be dealt with now, i.e. move semantics, which obviously C does not have nor will it likely ever.

In the example above, the question of "do I put defer before or after the `if err != nil` check" is deferred to the programmer. RAII forces you to handle the complexity, defer lets you shoot yourself in the foot.

Re: Defer available in gcc and clang

#139

Earlier quoted context omitted.

But it does keep one in the habit of using NULL checks.

It is pointless, because in Linux all you get is a virtual address. Physical backing is only allocated on first use. In other words, the first time you access a "freshly allocated" non-null pointer you may get a page fault due to insufficient physical memory.

By default, yes. You can configure it to not overcommit

Re: Defer available in gcc and clang

#140
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…

One small nitpick: you don't need check before `free` call, using `free(NULL)` is fine.

You're right that it's not needed in my example but sometimes the thing that you're freeing has pointers inside it which themselves have to be freed first and in that case you need the if.

There are several other issues I haven't shown like what happens if you need to free something only when the return code is "FALSE" indicating that something failed.

This is not as nice as defer but up till now it was a comparatively nice way to deal with those functions which were really large and complicated and had many exit points.

Post reply on HN