RAII is one of the best things about C++, and I'm excited for similar functionality in C. GCC's __cleanup__ is a poor substitute for a fully-baked addition to the language.
From skimming through the paper, it looks like there's an open discussion about the 'guard' keyword and scoping. I know that the scoping rules are tricky.
Would it make sense for defer statements to be attached to a variable's scope instead of a scope block? It would look something like GCC's __cleanup__, except that it could run an arbitrary statement/block instead of a callback. Scope-level defer() could be specified by attaching to a depth number.
If anybody involved in the paper is reading this, what would you think about this syntax?
//---------- Attaching a defer() to a variable's scope -----------//
int main(void) {
int *dummy = malloc(sizeof(int));
defer (dummy) {
printf("This statement prints second.\n");
free(dummy);
}
printf("This statement prints first.\n");
}
//------- Attaching a defer() to the current block's scope -------//
int main(void) {
int *dummy;
do {
dummy = malloc(sizeof(int));
defer (0) {
printf("This statement prints second.\n");
free(dummy);
}
printf("This statement prints first.\n");
} while (0);
printf("This statement prints third.\n");
}
//-------- Attaching a defer() to a parent block's scope ---------//
int main(void) {
int *dummy;
do {
do {
dummy = malloc(sizeof(int));
defer (1) {
printf("This statement prints third.\n");
free(dummy);
}
printf("This statement prints first.\n");
} while (0);
printf("This statement prints second.\n");
} while (0);
printf("This statement prints fourth.\n");
}
This syntax would eliminate the need for an explicit guard keyword, and would also make for a straightforward porting process for all code that currently uses __cleanup__. It also feels a little more C-like to me, in that it resembles the look-and-feel of other control-flow statements.In my example, defer() with a variable-name would attach itself to the variable's scope, and would execute when the variable leaves scope.
And defer() with an integer would attach itself to [current_scope_level - target_value]. So a defer(0) would trigger at the end of the current block scope, and defer(1) would trigger at the end of the parent block scope. Combined with generic {} blocks, you could get the same behavior provided by the paper's suggested guard keyword.