the “fix” is to move the errdefer code into one of the catch statements in the block (or to move the block to a function)
@dhw9406 the point is that the errdeferis tied to block scope, but the trigger condition for all errdefer statements is “return err”, which break :blk err is technically not.
If the trigger condition for defer is block scope exit, but the trigger condition for errdefer is function returns an error, this seems inconsistent to me. Thinking about it further, since blocks have ‘output values’ (not sure what the right verbiage is here), and block scope exit is used (by defer, break, etc) for control flow, it would not be inconsistent to say that errdefer should fire on block scope exit if the result value of the block is an error.
One counter argument, I suppose, would be that one may not want that error clean up code to run that early, but in that case the errdefer could just be moved to right after the block.
errdefer either: at normal function scope exit, nothing happens. if instead function scope is exited by return err , it should run
And this second version still correctly describes the current behavior. Which, to me, says that errdefer is in fact tied to function scope, because the only way for it to run on block scope exit is through a function return. And this is surprising to me. Not necessarily incorrect, but maybe incorrect.
one could write this, true! as you know, it’s a testable assertion that you are making, so let’s test it.
const std = @import("std");
pub fn main() !void {
try foo(false); // replace with true if you'd like
}
fn foo(in: bool) !void {
{
errdefer std.debug.print("errdefer!\n", .{});
if (in) return error.Foo;
}
return error.Bar;
}
in accordance with what I wrote, this program does not print errdefer! when run as written, but it does do so if you replace try foo(false); with try foo(true);
The way in which errdefer is scoped is clear to me now; thanks for the code! Code is usually the best way to communicate precisely. I still think that it’s a little surprising that an errdefer in a block does not fire when that block results in an error, but until I’m off my phone and at my computer to write some experiments in code, I can’t really see which cases argue for one semantic over the other. This has been enlightening, though, so thanks!