I just wish C had something like defer in go, That would cover most cases.
If you're willing to use macros, this can do the trick. Return and break will preempt the expression, but continue should work fine. #define DEFER(EXPR) for(int _tmp=1; _tmp; _tmp=0,(EXPR)) Example: char * data = malloc(32); DEFER(free(data)) { // do stuff }
Show HN: A simple garbage collector for C
11–20 of 62 posts
Re: Show HN: A simple garbage collector for C
#12Earlier quoted context omitted.
Defer can be emulated with the block extensions of Clang and GCC [0], though I'm not sure how much I'd like to see something like that in a codebase. [0] https://web.archive.org/web/20180426195701/http://fdiv.net/2...
That link seems to be broken? Nothing opens when I click it.
The original link works.
Re: Show HN: A simple garbage collector for C
#13I just wish C had something like defer in go, That would cover most cases.
If you're willing to use macros, this can do the trick. Return and break will preempt the expression, but continue should work fine. #define DEFER(EXPR) for(int _tmp=1; _tmp; _tmp=0,(EXPR)) Example: char * data = malloc(32); DEFER(free(data)) { // do stuff }
Re: Show HN: A simple garbage collector for C
#14I just wish C had something like defer in go, That would cover most cases.
If you're willing to use macros, this can do the trick. Return and break will preempt the expression, but continue should work fine. #define DEFER(EXPR) for(int _tmp=1; _tmp; _tmp=0,(EXPR)) Example: char * data = malloc(32); DEFER(free(data)) { // do stuff }
Re: Show HN: A simple garbage collector for C
#15Earlier quoted context omitted.
If you're willing to use macros, this can do the trick. Return and break will preempt the expression, but continue should work fine. #define DEFER(EXPR) for(int _tmp=1; _tmp; _tmp=0,(EXPR)) Example: char * data = malloc(32); DEFER(free(data)) { // do stuff }
Perhaps I'm misunderstanding this, but this doesn't solve the problem at all -- returning within the block statement wouldn't call the deferred expression, which is entirely the point of a defer statement, no? If control is guaranteed to reach the end of the block statement, of course; but requiring such a constraint would make this defer very handicapped. You have tons of function exit points and you most likely wan…
Most of the challenge in writing code with a single return seems to come from the fact that I'm not used to doing it. Of course, sometimes it leads to heavily nested control flow, although I'm not sure yet whether or not I mind that. It does certainly simplify reasoning about control flow though, especially in large functions.
That all being said, I'd still rather just have defer.
Re: Show HN: A simple garbage collector for C
#16Earlier quoted context omitted.
If you're willing to use macros, this can do the trick. Return and break will preempt the expression, but continue should work fine. #define DEFER(EXPR) for(int _tmp=1; _tmp; _tmp=0,(EXPR)) Example: char * data = malloc(32); DEFER(free(data)) { // do stuff }
Perhaps I'm misunderstanding this, but this doesn't solve the problem at all -- returning within the block statement wouldn't call the deferred expression, which is entirely the point of a defer statement, no? If control is guaranteed to reach the end of the block statement, of course; but requiring such a constraint would make this defer very handicapped. You have tons of function exit points and you most likely wan…
Alternatively you might be able to use nested functions to guard against a stray return but that's not standard.
Re: Show HN: A simple garbage collector for C
#17Earlier quoted context omitted.
Perhaps I'm misunderstanding this, but this doesn't solve the problem at all -- returning within the block statement wouldn't call the deferred expression, which is entirely the point of a defer statement, no? If control is guaranteed to reach the end of the block statement, of course; but requiring such a constraint would make this defer very handicapped. You have tons of function exit points and you most likely wan…
Yes, the only way I could imagine implementing a "proper" defer in C would be to use (like for most insane C hacks) setjmp/longjmp. I'm fairly sure it's explicitly forbidden by the Geneva Conventions though. Alternatively you might be able to use nested functions to guard against a stray return but that's not standard.
Re: Show HN: A simple garbage collector for C
#18I just wish C had something like defer in go, That would cover most cases.
The implementation is very simple, it's just using a class for its destructor:
template
class final_act
{
public:
explicit final_act(F f) noexcept : f_(std::move(f)), invoke_(true) {}
final_act(final_act&& other) noexcept : f_(std::move(other.f_)), invoke_(other.invoke_)
{
other.invoke_ = false;
}
final_act(const final_act&) = delete;
final_act& operator=(const final_act&) = delete;
~final_act() noexcept
{
if (invoke_) f_();
}
private: F f_;
bool invoke_;
};Source: https://github.com/microsoft/GSL/blob/ebe7ebfd855a95eb937831...
Re: Show HN: A simple garbage collector for C
#19Earlier quoted context omitted.
Perhaps I'm misunderstanding this, but this doesn't solve the problem at all -- returning within the block statement wouldn't call the deferred expression, which is entirely the point of a defer statement, no? If control is guaranteed to reach the end of the block statement, of course; but requiring such a constraint would make this defer very handicapped. You have tons of function exit points and you most likely wan…
Regarding having tons of exit points, I find it actually adds no more cognitive load to use only a single return per function, compared to having multiple returns and keeping resource-freeing up-to-date for each. Most of the challenge in writing code with a single return seems to come from the fact that I'm not used to doing it. Of course, sometimes it leads to heavily nested control flow, although I'm not sure yet w…
For instance parameter validation is one instance where I think an early return is very much warranted. There you typically have no cleanup to do since it's effectively the prelude of the function.
Regarding nested error handling, I prefer the "goto fail" pattern. Some people are opposed to the use of goto as a matter of principle but I think in this case it's fine. It's effectively the poor man's RAII when you don't have destructors.
Re: Show HN: A simple garbage collector for C
#20Earlier quoted context omitted.
Yes, the only way I could imagine implementing a "proper" defer in C would be to use (like for most insane C hacks) setjmp/longjmp. I'm fairly sure it's explicitly forbidden by the Geneva Conventions though. Alternatively you might be able to use nested functions to guard against a stray return but that's not standard.
How would you implement defer with setjmp/longjmp? I can’t think of anything off the top of my head.