I'm thinking quite straightforward:
File *file = open("foo.txt");
if (!file) return false;
defer {
file.close();
}
...
if (something) return false;
...
return true;
This is transformed to the following code (can be done when parsing):
File *file = open("foo.txt");
if (!file) return false;
...
if (something)
{
file.close();
return false;
}
...
file.close();
return true;
(It can also be handled with a jump obviously)
I would suggest the following:
- It's possible to use a plain return within a defer, it only exits the defer early (the defer acts as an anonymous function / closure).
- It's possible to stack defers
One thing worth discussing is what happens when you actually put a defer in a block.
Consider this:
...
defer { ... } // A
....
{
defer { ... } // B
} // C
....
return; // D
In this case it's unclear whether the best thing would be defer B to act on exit of the block (at point C) or (point D, before defer at A is executed.
But if we pick point C (which would be nice), we have some choices to make. For example, when is the defer called here:
if (some_condition) defer { .... }; // A
if (some_condition) {
defer { .... }; // B
}
if (some_condition) {
defer { .... }; // C
x = y;
} // D
...
return; // E
One probably wants the defer of both A and B to occur at E, but the defer at C is probably intended for D.
Go makes the decision to use E for all defers, while Swift would allow execute A and B directly, just like defer at C.
Zig follows Swift and adds an "errdefer" as a special case defer on error exit.