With the proposed
redeferkeyword, 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
deferanderrdeferbecomes 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.