C++ supports this sort of thing directly. It says something about C++ takeup that anyone would bother adding this kludge to C. Many people are scared of C++. The language has become incredibly complex.
C++ templates are Turing-complete. You can do arbitrary computation at compile time. Once this was discovered, ever-fancier templates became a basic part of C++. (Take a look at the huge templates that implement "max" and "min".) Then the C++ standards committee went off into template la-la land, focusing on adding features to make the template system more powerful. After a decade of this, many standard templates are now at the "you are not supposed to understand this" level.
This has scared people off of C++, which is why there's still much work in standard C. So now we're seeing features added to C to solve specific problems, but without an architecture.
"Defer" is troublesome, because dealing with errors in deferred statements is hard. C++ has the same problem with destructors. A "with" clause, which LISP introduce as "with-open-file" and Python also supports, is a better way to do this. Python's combination of "with" and exception handling can handle an error when closing out a resource, and get all the nested resources closed out properly. Few other languages even try to get that right.
Not touching on the rest of what you said, but what's so bad about min? Apart from some internal clang stuff, like odd names and macros, it looks okay - I can see what the function is doing.
Because a macro in C/C++ is just text expansion, the given implementation will evaluate its arguments more than once, which will not be obvious at the "call" site and could have unintended consequences if the expressions have side-effects.
Is there another way to do it as a macro that avoids this? How do you have temporary variables potentially in the middle of a larger expression, e.g. if (min(a,b) == 3) {...}
I think I just see it as different niches. C++ only adds to the code after a certain amount of complexity because there is so much magic its hard to manually translate to assembly in your head (at times). I certainly don't know much about c++ >03; the additions have been.... Probably not worth using over c for the massive probability and ability to contribute easily for small tools.
Not the same semantics, as least compared to Golang. This is block-scoped, but "defer" in Go is function-scoped and has highly dynamic semantics—for example, call it in a loop and the compiler may not be able to statically prove how many times it will run.
(Note that, IMO, the semantics of the feature as implemented in the article are preferable to those of Golang, so I wouldn't personally go to the effort of trying to duplicate Go's behavior.)
Unless I'm mistaken, `__attribute__((cleanup))` is function-, not block-, scoped. The cleanup attribute is actually declared on the Block, which is kind of cute.
Instead, I'd suggest just making regular use of `__attribute__((cleanup))` in C under GCC or Clang and avoiding C blocks entirely. In this case you could do something like:
#define AUTOCLOSE_FILE(n) __attribute__((cleanup(autoclose_file))) n = NULL
void
autoclose_file(FILE *f)
{
if (f)
fclose(f);
}
int
main(...)
{
FILE AUTOCLOSE_FILE(*a), AUTOCLOSE_FILE(*b);
a = fopen("foo");
if (!a)
return;
b = fopen("bar");
if (!b)
return;
...
}
This isn't really C, though. It's "Clang C" - which is arguably better than C, and I wouldn't want to be stuck writing non-Clang C, but it should be represented correctly.
The canonical method in C is to jump to a named label which hosts some functions to unwind/close any open descriptors or operations. As it involves the use of a goto statement, it drives certain people mad.
Last time I looked at it, BOOST_SCOPE_EXIT_ALL generated similarly atrocious code, which is a shame because you can write a zero-cost construct in C++11 very easily.
the problem with goto for error handling is possibility of programmer error: you have to keep track of the order of labels yourself, whereas defer does that for you. i won't comment on anti-goto fascism.
I don't think that hacker news is all about one thing.
Furthermore, it's fun to play with this, but it is undeniably not c. If you have access to clang everywhere (or gcc w/ blocks) and you're OK with the tradeoffs, have at it. :)
C++ templates are Turing-complete. You can do arbitrary computation at compile time. Once this was discovered, ever-fancier templates became a basic part of C++. (Take a look at the huge templates that implement "max" and "min".) Then the C++ standards committee went off into template la-la land, focusing on adding features to make the template system more powerful. After a decade of this, many standard templates are now at the "you are not supposed to understand this" level.
This has scared people off of C++, which is why there's still much work in standard C. So now we're seeing features added to C to solve specific problems, but without an architecture.
"Defer" is troublesome, because dealing with errors in deferred statements is hard. C++ has the same problem with destructors. A "with" clause, which LISP introduce as "with-open-file" and Python also supports, is a better way to do this. Python's combination of "with" and exception handling can handle an error when closing out a resource, and get all the nested resources closed out properly. Few other languages even try to get that right.