Proposal: A New redefer Keyword for Function-Scoped Deferred Execution

With the proposed redefer keyword, the solution becomes elegantly simple:

It’s not clear whether your example is correct. If your code is inside a block, then the container array gets freed before the inner arrays (since defer would run at the end of the block but redefer runs at the end of the function.

Having a different kind of defer seems like it could be a footgun. You can also simulate what your proposed redefer does today with something like this:

// put this at the top of the function
var foo: ?T = null;
defer if (foo) {
    // do cleanup
}

// ...later on in the function

foo = ...; // equivalent to rdefer

Implementing the correct cleanup logic for all failure paths using only defer and errdefer becomes exceptionally complex and unwieldy.

Here’s my attempt:

    var al: std.ArrayListUnmanaged([]f64) = .{};
    defer al.deinit(allocator);
    errdefer for (al.items) |row| {
        allocator.free(row);
    };
    try al.ensureTotalCapacity(allocator, 2);
    for (0..2) |_| {
        al.appendAssumeCapacity(try allocator.alloc(f64, 2));
    }

This should behave correctly and even does so if it’s inside a block.

P.S. actually your example may not be correct even if it’s not inside a sub-block. It would depend on if defer’s and rdefer’s get executed in the same reverse order, or if you first execute all defers and then all rdefers…if it’s the latter then example would still be incorrect.

1 Like