Live data from Hacker News

Defer available in gcc and clang

gustedt.wordpress.com

161–170 of 262 posts

Re: Defer available in gcc and clang

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

Yes, defer is absolutely a form of hidden control flow, even if it's less egregious than exceptions.

Re: Defer available in gcc and clang

#162
post #140

Earlier quoted context omitted.

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.

That's certainly one way to do it if you're writing all the code.

Re: Defer available in gcc and clang

#163
post #34

Earlier quoted context omitted.

If you're teaching them to write an assembler, then it may be worth teaching them C, as a fairly basic language with a straightforward/naive mapping to assembly. But for basically any other context in which you'd be teaching first-year CS students a language, C is not an ideal language to learn as a beginner. Teaching C to first-year CS students just for the heck of it is like teaching medieval alchemy to first-year…

C is the best language to learn as a beginner.

At no point in human history has C been the best language for beginners. C was, like Javascript, hacked together in a weekend by someone who wished they could be using a better language. It was burdened with flaws from the outset and considered archaic in its design almost immediately. The best thing that can be said about the design of C is that it's at least a structured programming language, which is damning with faint praise.

Re: Defer available in gcc and clang

#164
post #114

Earlier quoted context omitted.

To be fair, there were multiple wrongs in that piece of code: avoiding typing with the forward goto cleanup pattern; not using braces; not using autoformatting that would have popped out that second goto statement; ignoring compiler warnings and IDE coloring of dead code or not having those warnings enabled in the first place. C is hard enough as is to get right and every tool and development pattern that helps avoid…

The forward goto cleanup pattern is not something "wrong" that was done to "avoid typing". Goto cleanup is the only reasonable way I know to semi-reliably clean up resources in C, and is widely used among most of the large C code bases out there. It's the main way resource cleanup is done in Linux. By putting all the cleanup code at the end of the function after a cleanup label, you have reduced the complexity of res…

In theory, for straight-line code only, the If Statement Ladder of Doom is an alternative:

  int ret;
  FILE *fp;
  if ((fp = fopen("hello.txt", "w")) == NULL) {
      perror("fopen");
      ret = -1;
  } else {
      const char message[] = "hello world\n";
      if (fwrite(message, 1, sizeof message - 1, fp) != sizeof message - 1) {
          perror("fwrite");
          ret = -1;
      } else {
          ret = 0;
      }
  
      /* fallible cleanup is unpleasant: */
      if (fclose(fp) 
It is in particular universal in Microsoft documentation (but notably not actual Microsoft code; e.g. https://github.com/dotnet/runtime has plenty of cleanup gotos).

In practice, well, the “of doom” part applies: two fallible functions on the main path is (I think) about as many as you can use it for and still have the code look reasonable. A well-known unreasonable example is the official usage sample for IFileDialog: https://learn.microsoft.com/en-us/windows/win32/shell/common....

Re: Defer available in gcc and clang

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

What's the use-case for block-level defer?

In a tight loop you'd want your cleanup to happen after the fact. And in, say, an IO loop, you're going to want concurrency anyway, which necessarily introduces new function scope.

Re: Defer available in gcc and clang

#166
post #89
post #87

Earlier quoted context omitted.

Because they are all the consequence of holding it wrong, avoiding RAII solutions. Working with native C APIs in C++ is akin to using unsafe in Rust, C#, Swift..., it should be wrapped in type safe functions or classes/structs, never used directly outside implementation code. If folks actually followed this more often, there would be so much less CVE reports in C++ code caused by calling into C.

If I'm gonna write RAII wrappers around every tiny little thing that I happen to need to call once... I might as well just use Rust and make the wrappers do FFI. If I'm constructing a particular C object once in my entire code base, calling a couple functions on it, then freeing it, I'm not much more likely to get it right in the RAII wrapper than in the one place in my code base I do it manually. At least if I have…

if you do it once - why do you care about "ugly" scope_exit? btw, writing such wrappers is easy and does not require a lot of code.

Re: Defer available in gcc and clang

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

[deleted]

Re: Defer available in gcc and clang

#168
post #152

Earlier quoted context omitted.

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.

> `defer` is still in "spooky action at a distance" category

Agree, this is also why I'm a bit weary of it.

What brings me on the "pro" side is that, defer or not defer, there will need to be some kind of cleanup anyway. It's just a matter of where it is declared, and close to the acquisition is arguably better.

The caveat IMHO is that if a codebase is not consistent in its use, it could be worst.

Re: Defer available in gcc and clang

#169
post #4

A long overdue feature. Though I do wonder what the chances are that the C subset of C++ will ever add this feature. I use my own homespun "scope exit" which runs a lambda in a destructor quite a bit, but every time I use it I wish I could just "defer" instead.

Just hope those lambdas aren't throwing exceptions ;)

Re: Defer available in gcc and clang

#170
post #114

Earlier quoted context omitted.

The forward goto cleanup pattern is not something "wrong" that was done to "avoid typing". Goto cleanup is the only reasonable way I know to semi-reliably clean up resources in C, and is widely used among most of the large C code bases out there. It's the main way resource cleanup is done in Linux. By putting all the cleanup code at the end of the function after a cleanup label, you have reduced the complexity of res…

In theory, for straight-line code only, the If Statement Ladder of Doom is an alternative: int ret; FILE *fp; if ((fp = fopen("hello.txt", "w")) == NULL) { perror("fopen"); ret = -1; } else { const char message[] = "hello world\n"; if (fwrite(message, 1, sizeof message - 1, fp) != sizeof message - 1) { perror("fwrite"); ret = -1; } else { ret = 0; } /* fallible cleanup is unpleasant: */ if (fclose(fp) It is in partic…

[deleted]
Post reply on HN