I’ve always considered “defer” an inelegant kludge in comparison to RAII for automatic cleanup of resources. It’s surprising that the C standards committee is considering adding that to the language. Then again, nearly none of the syntactic C features post-C89 have been very compelling or widely adopted.
Also defer runs even if your code panic which is great.
A Defer Mechanism for C
121–130 of 248 posts
Re: A Defer Mechanism for C
#122Despite 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,…
> One of the key interest of C compared to more recent languages is that everything is explicit. With macros this is not exactly true. I gesture towards the GObject system for an extremely complex situation in big important production software.
Re: A Defer Mechanism for C
#123Earlier quoted context omitted.
I would strongly disagree on RAII being a kludge in C++. The language feature that enables it is deterministic destructors, whose primary purpose is to ensure that allocated resources are deallocated. RAII is one particular use of destructors. The primary goal is to have the object be the thing that owns a resource, not the calling scope. In terms of usability, destructors allow for resource management that is far ea…
I do feel that RAII is a little bit ruined by the fact that you cannot declare anonymous object instances. For example, I cannot write: lock (mutex); Expecting to declare an anonymous lock with the mutex passed in, as this gets parsed as a declaration of a lock called mutex (hopefully lock doesn’t have a default constrictor and I at least get an error). Instead I have to bake my lock: lock l(mutex); Often I have obje…
#define LOCK(mutex) lock lock##__LINE__(mutex)
Or even C compatible scoped locks: #define SCOPED_LOCK(mutex) \
for (int i##__LINE__ = lock_mutex(mutex), 1; \
i##__LINE__ --; \
unlock_mutex(mutex))
Use like SCOPED_LOCK(foo->mutex) {
do_stuff();
}Re: A Defer Mechanism for C
#124In 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…
for i := 0; i Re: A Defer Mechanism for C
#125In 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…
This case of the defer in the loop is frequently cited, probably because it is a problematic case. However, I looked at a lot of real code and the only case I found of resources being allocated in a loop they were allocated at the beginning of the loop and deallocated at the end. Another option we are considering is to use the scope for the guarded block. In this case, deferred statements would be executed at the end of each iteration of the for loop which would be ideal for this sort of code. For example, you could rewrite this function using defer:
https://github.com/openssl/openssl/blob/a829b735b645516041b5...
like this:
for (;;) {
raw = 0;
ptype = 0;
i = PEM_read_bio(bp, &name, &header, &data, &len);
defer {
OPENSSL_free(name);
name = NULL;
OPENSSL_free(header);
header = NULL;
OPENSSL_free(data);
data = NULL;
}
...
} else {
/* unknown */
}
} // end for loop, run deferred statementsRe: A Defer Mechanism for C
#126In 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…
void reverse_bitstream(void * read_ctx, void * write_ctx) {
guard {
while(has_more_bits(read_ctx)) {
int b = read_bit(read_ctx);
if (b == 0) defer write_bit(write_ctx, 0);
else if(b == 1) defer write_bit(write_ctx, 1);
}
}
}Re: A Defer Mechanism for C
#127In 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…
I suspect it will come with some really big caveats. For instance what you wrote shouldn't compile, because i's storage duration doesn't extend to the end of the guard block. If you write 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…
This still makes it really easy to overflow your stack, especially if for example your loop count above can come from user input. This is dangerous for all the same reasons that variable-length arrays are dangerous.
Re: A Defer Mechanism for C
#128In 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…
I got the impression that the proposal still has some aspects of the design that are open for discussion, including whether it should be static or dynamic, and whether it should capture the variables by value or by reference. (These are discussed in pages 13-16)
Re: A Defer Mechanism for C
#129Earlier quoted context omitted.
I suspect it will come with some really big caveats. For instance what you wrote shouldn't compile, because i's storage duration doesn't extend to the end of the guard block. If you write 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…
The proposal poses object value capture as an open question. See heading "Should object values be captured?" on page 14 of the proposal: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2542.pdf