Live data from Hacker News

Defer available in gcc and clang

gustedt.wordpress.com

141–150 of 262 posts

Re: Defer available in gcc and clang

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

Re: Defer available in gcc and clang

#142
post #78

Earlier quoted context omitted.

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

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 to something you do every handful of lines.

String literals in C++ are 'const char *' instead of 'char *'. While this is more technically correct, it means you have to add casts to 'char *' all over the place. Plenty of C APIs are really not very ergonomic when string literals aren't 'char *'.

And the big one: C++ doesn't have C's struct literals. Lots of C APIs are super ergonomic if you call them like this:

    some_function(&(struct params) {
        .some_param = 10,
        .other_param = 20,
    });
You can't do that in C++. C++ has other features (such as its own, different kind of aggregate initialization with designated initializers, and the ability for temporaries to be treated as const references) which make C++ APIs nice to work with from C++, but C APIs based around the assumption that you'll be using struct literals aren't nice to use from C++.

If you wanna use C, use C. C is a much better C than C++ is.

Re: Defer available in gcc and clang

#143
post #13

I’m just going to start teaching classes of C programming to university first-year CS students. Would you teach `defer` straight away to manage allocated memory?

No, but also skip malloc/free until late in the year, and when it comes to heap allocation then don't use example code which allocates and frees single structs, instead introduce concepts like arena allocators to bundle many items with the same max lifetime, pool allocators with generation-counted slots and other memory managements strategies.

Is there any C tutorials you know that do that so I can try to learn how to do it?

Re: Defer available in gcc and clang

#144
post #86

Earlier quoted context omitted.

In general it would help if you would spend some text on describing what features of C99 are missing in other languages. Giving some code and assume that the reader will figure it out is not very effective. As far as I can tell, Rust can do what it is in your example (which different syntax of course) except for this particular way of initializing an array. To me, that seems like a pretty minor syntax issue to that c…

I can show more code examples instead: E.g. notice how here in Rust each nested struct needs a type annotation, even though the compiler could trivially infer the type. Rust also cannot initialize arrays with random access directly, it needs to go through an expression block. Finally Rust requires `..Default::default()`: https://github.com/floooh/sokol-rust/blob/f824cd740d2ac96691... Zig has most of the same issues a…

In Rust you can do "fn new(field: Field) -> Self { Self { field } )" This is in my experience the most common case of initializers in Rust. You don't mention one of the features of the Rust syntax, that you only have to specify the field name when you have a variable with the same name. In my experience, that reduces clutter a lot.

I have to admit, the ..Default::default() syntax is pretty ugly.

In theory Rust could do "let x: Foo = _ { field }" and "Foo { field: _ { bar: 1 } }". That doesn't even change the syntax. Its just whether enough people care.

Re: Defer available in gcc and clang

#145
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 wonder what the thought process of the Go designers was when coming up with that approach. Function scope is rarely what a user needs, has major pitfalls, and is more complex to implement in the compiler (need to append to an unbounded list).

> I wonder what the thought process of the Go designers was when coming up with that approach.

Sometimes we need block scoped cleanup, other times we need the function one.

You can turn the function scoped defer into a block scoped defer in a function literal.

AFAICT, you cannot turn a block scoped defer into the function one.

So I think the choice was obvious - go with the more general(izable) variant. Picking the alternative, which can do only half of the job, would be IMO a mistake.

Re: Defer available in gcc and clang

#146
post #62

Earlier quoted context omitted.

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.

When talking about K&R C and the assembler provided by UNIX System V, yes.

Even today, the only usable Assemblers on UNIX platforms were born in PC or Amiga.

Re: Defer available in gcc and clang

#147
post #142

Earlier quoted context omitted.

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

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 for feature utility is completely different than mine. I suspect for most people that's not the case, and most of the time the reason to pick C over C++ is ideological, not because of these 2 pieces of syntax sugar.

"I like it" is a good enough reason to use something, my original comment is to the person who wants to use C but gets excited about features like this - I don't know how many of those people are aware of how trivially most of these things can be accomplished in C++.

Re: Defer available in gcc and clang

#148
post #44
post #37

Earlier quoted context omitted.

I get your point, though in the specific case of defer, looks like we both agree it's really a good move. No more spaghetti of goto err_*; in complex initialization functions.

>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 is an entirely different subject, of very few interest to people programming in X.

Re: Defer available in gcc and clang

#149
post #140

Earlier quoted context omitted.

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 comparative…

If you have something which contains pointers, you should have a destructor function for it, which itself should check if the pointer is not NULL before attempting to free any fields.
Post reply on HN