Earlier quoted context omitted.
As replied by someone else, by 'random' I did not mean really 'randomly', because the machine is determinist and follow a logic. But more that there is so much magic and abstractions that it is very hard for a dev to have a clear view of what is going on and what to expect. He has to 'guess' instead of just read the code. For that, I guess that it is similar to the current question of accountability of decisions made…
> As an example of my point, I would refer to the 'garbage collection' issues of a language like 'java' Two languages could hardly be less alike than Java and C++ - the latter is not garbage collected and where destructors are called is completely predictable.
A Defer Mechanism for C
71–80 of 248 posts
Re: A Defer Mechanism for C
#72Earlier quoted context omitted.
How can you get away from having an explicit guard block? Without one, you couldn't 'defer' to the end of a containing block from within an if/while/do/for/etc. block. When/where the deferred code is executed has to be specified some way so an explicit marker for the defer 'scope' is surely required without severely limiting the utility of the feature.
Starting in page 16, there is a section called "Do we want a guard keyword?" that talks about this. They give an example showing that deferring to the end of the containing block is possible without the guard keyword, although it's a bit wonky, requiring to duplicate the "if". With guard keyword: guard { void *ptr = malloc(12); if (ptr) { defer free(ptr); // Use ptr } // Use ptr some more } // free ptr here Without g…
In a more realistic case, say some object was handed off so it shouldn't be cleaned up anymore, you can just add a should_cleanup flag and check it in the defer block. There's really no need for guard.
Their other example for guard, running defer in a loop, requires closures. This means it requires dynamic memory allocation and so the complexity goes through the roof.
Re: A Defer Mechanism for C
#73while(TRUE)
{
a = malloc(sizeof *a);
if(a == NULL)
break;
*a = malloc(1024);
if(*a == NULL)
break;
if(!do_some_other_tests(a))
break;
return a;
}/* cleanup /
if(a == NULL)
return;
if(a != NULL) free(*a);
free(a);
alt:void * * a = NULL;
switch(TRUE)
{
defaultt :
a = malloc(sizeof *a);
if(a == NULL)
break;
*a = malloc(1024);
if(*a == NULL)
break;
if(!do_some_other_tests(a))
break;
return a;
}/* cleanup /
if(a == NULL)
return;
if(a != NULL) free(*a);
free(a);Re: A Defer Mechanism for C
#74Please just standardize the already existing attribute((cleanup)) mechanism which is already being used by lots of Linux software. This new mechanism is incompatible while bringing no benefits.
I would tend to agree with you. Unfortunately this proposal is for much more than just block scope cleanup. This proposal contains a specification for complete stack unwinding in C. It doesn't just specify defer, but also panic and recover, which jumps between functions and cleans up guard blocks across stack frames. It's essentially exceptions for C. This is frankly horrifying and I can't believe the C standards com…
Also, the defer syntax they're proposing seems nicer in terms of syntactic sugar (no need for a stub function), but at the same time the semantics seem ... weird. Having it tied to a variable makes more sense, and sidesteps a whole bunch of weird situations (like loops with defer statements).
Re: A Defer Mechanism for C
#75Please just standardize the already existing attribute((cleanup)) mechanism which is already being used by lots of Linux software. This new mechanism is incompatible while bringing no benefits.
Defer has the benefit of being dynamic vs the scope tied cleanup.
Re: A Defer Mechanism for C
#76Earlier quoted context omitted.
Sure. But defer just changes the problem from forgetting to write free to forgetting to write defer. So we’re not really talking about provably correct solutions... just things that can work. And I think a context or just manually freeing can work nicely.
> Sure. But defer just changes the problem from forgetting to write free to forgetting to write defer. Yes, which is a much better formulation.
So it adds a new way to misinterpret the code: is cleanup deferred or not?
Re: A Defer Mechanism for C
#77In its current form, this is really stupid, because of something like this: guard { for (int i = 0; i Now the compiler has to: 1. implement some side of capture/closure mechanism to keep all the 'i's to the end of the guard block 2. do dynamic allocation to store the closures so they can be executed at the end did the scope 1 seems like too much work for such a feature, and 2 is a massive no. Implicit dynamic allocat…
Still, I agree that this is not "nice and clean". Ultimately it doesn't feel like something that belongs in C.
Re: A Defer Mechanism for C
#78In its current form, this is really stupid, because of something like this: guard { for (int i = 0; i Now the compiler has to: 1. implement some side of capture/closure mechanism to keep all the 'i's to the end of the guard block 2. do dynamic allocation to store the closures so they can be executed at the end did the scope 1 seems like too much work for such a feature, and 2 is a massive no. Implicit dynamic allocat…
guard {
int i;
for (i=0; i
I would expect foo(n) to be called n times. That is, variables won't be captured, it would work literally as if you wrote "foo(i)" n times at the end of the guard block. It's a footgun, but everything in C is a footgun and this behaviour is not surprising to me as a C developer.So I expect the implementation would be
1. If a defer block references variables which do not live to the end of the guard block, the program is malformed (compiler error).
2. Compile each defer block as if it was written at the end of the guard block. What order the defer blocks are stored in is implementation-defined
3. Put a pointer on the stack each time a defer statement executes pointing to the compiled defer statement.
With this each defer statement is just a few bytes of overhead added to the stack and you can do it in a loop, though it may not do what you expect if you come from Go. For the example I expect the compiler to emit code similar to:
struct defer_node {
void **label;
struct defer_node *next;
};
struct defer_node *defer_start=0;
int i;
for (i = 0; i label = &defer_stmt0;
defer_new->next = defer_start;
defer_start = defer_new;
}
while (defer_start) {
goto *defer_start->label;
defer_stmt_exit:
defer_start = defer_start->next;
}
return;
/* or break; or continue; whatever is appropriate for the enclosing block */
defer_stmt0:
foo(i);
goto defer_stmt_exit;
This makes defer more or less just a mechanical transformation of code that can be expressed with existing C primitives and without requiring dynamic memory. I think it would be a good addition to C's structured programming elements.Re: A Defer Mechanism for C
#79GCC has a similar extension for defering to end of scope, which is basically most of use cases(cleanup function is usually free or some destructor/sanity check function). https://echorand.me/site/notes/articles/c_cleanup/cleanup_at...
Re: A Defer Mechanism for C
#80Despite being convenient,I have the feeling that it might be a bad idea. One of the key interest of C compared to more recent languages is that everything is explicit. With a finger you can follow the code as it runs and know exactly what is going on and when exactly. At the opposite, there is c++ that does a lot of things automagically. And it is often hard to understand why you suddenly get a segfault out of blue,…
Despite being convenient,I have the feeling that it might be a bad idea. What is "I am thinking of using C?"