#Understanding errdefer Behavior in Zig

1 messages · Page 1 of 1 (latest)

tiny ore
#

I am new to Zig and trying to understand how the errdefer keyword works. Consider the following code:

var v1 = try fun1();      // If this line fails, what happens next?
errdefer v1.destroy();    // Will this errdefer execute?

var v2 = try fun2();      
errdefer v2.destroy();    // Will this errdefer execute if `fun1()` fails?

My questions:

If `fun1()` fails, v1 is never initialized. Since `errdefer` executes only when an error occurs, would calling `v1.destroy()` be undefined behavior?
If `fun1()` fails, will `errdefer v2.destroy();` still be registered, or is it skipped entirely because `fun2()` was never called?

Thanks in advanced.

nova flower
#

so there are a couple of pieces at play here

the try statement takes an expression which returns an error union. it is syntax sugar for: foo() catch |err| return err;
if that error union is in the error state (so it's returning an error), then it takes that error and returns it. if it isn't an error, then it unwraps the error union and results in the payload. so if it returns !void it evalutes to void, etc.

defer and errdefer work in the exact same way, the only difference being that the errdefer body is ran if the return value is an error of some sort (so like an error union where the error state is active). similar to how defer works, the control flow needs to pass through the statement in order for it to be "registered".

in your example, if fun1 returns an error, the function execution will stop there and the error will be returned. the errdefer v1.destroy() will never be reached and it will never "register".
i think that answers your second question as well. the defer type statements aren't tied to anything, they are just stand along pieces of control flow. they don't need to be underneath a function, but it's just really common since you can leak memory if a subsequent function returns an error without you registering an errdefer for something managed above.