Hacker News new | ask | show | jobs
by wayne 1254 days ago
While not trivial, the problem of remembering to free everything is slightly simpler when you don't have to worry about exceptions.
3 comments

Yes, just put a "if (errno) goto err" after every function call in your program.

(That was sarcasm, FYI. Obviously it's 2023 and nobody wants to do manual function calling boilerplate as if you're programming 1960's assembly.)

I used to do `if (errno) goto err;` a lot. I eventually realized that nested functions did the job much nicer:

    void err() { printf("oops, we failed"); }
    ...
    if (errno) return err();
This cleaned up a lot of my code. (The optimizer would of course inline the function, and the common tail merging would automatically convert it to the goto version in the optimizer. So this was cost-free.)

Why C doesn't officially have nested functions is, well, that's C!

This is my one of my favourite patterns with nested functions - clean code, and avoid a ratsnest of 70s basic style GOTO.

It starts with one goto, then one more, then another.

The first goto is usually clever but then someone else arrives and hacks another one because they don't want to change the code too much.

Cleanup goto-style is hard to describe as a "rat's nest", since all the gotos in the same function go to the same label at the end that just does all the cleanup before returning. There's nothing clever about it, and many codebases wrap it into macros and such to make the syntax more concise and the intent explicit.
Cleanup is mostly fine but people see the goto fail then start using them for other things because there's already a goto there and thus congruent
> Why C doesn't officially have nested functions is, well, that's C!

Maybe some day it will. It should anyway

But GCC and Clang already support it, and while I can't find if MSVC does, it probably does

edit: also, now I see that the goto in if (errno) goto err is really just an (inlined) tail call!

MSVC does not support it.

In general, any random C compiler is likely to not support that feature, because the way it interacts with function pointers makes it unnecessarily complicated.

> unnecessarily complicated

Pascal could do it in the 1970s, and even Tiny Pascal could do it, see the listing for the compiler in BYTE.

https://archive.org/details/byte-magazine-1978-09

As for function pointers, a simple solution is to not allow them unless the function is declared `static`. `static` functions don't have a hidden static link.

The problem isn't doing it as such; ALGOL 60 could do nested functions just fine.

The problem is doing it in an ABI-compatible way when you already have an ABI. The gcc implementation of nested functions does that - they are compatible with regular function pointers - but at the cost of requiring executable stack on at least some platforms.

And for C compilers that aren't gcc, the question becomes: why partially implement a non-standard gcc feature?

Clang doesn't support the GNU C extension for nested functions.
I think Zig's defer and errdefer make this pattern slightly more tolerable, but proper RAII is indeed best

https://ziglang.org/documentation/master/#defer

https://ziglang.org/documentation/master/#errdefer

Well, to quote some Go..

  if err != nil {
    return nil, err
  }
*for some definition of nobody
but.. with RAII you don't either, that's the whole point
setjmp/longjump/signals