pub fn init(game_ctx: *Game) Self {
var this = Self.getDefault();
this.game_ctx = game_ctx;
this.body = std.ArrayList(rl.Vector2).init(Game.allocator);
defer this.setTail(); // sets this.tail to a pointer to the first element in the list
defer this.setHead(); // sets this.head to a pointer to the last element in the list
this.addBodyPart(0, 0);
this.addBodyPart(0, 1);
this.addBodyPart(1, 1);
return this;
}
when i run this i get an error somewhere down the line that the fields head and tail have both the value 0x0
when i have the init method without the defers:
pub fn init(game_ctx: *Game) Self {
var this = Self.getDefault();
this.game_ctx = game_ctx;
this.body = std.ArrayList(rl.Vector2).init(Game.allocator);
this.addBodyPart(0, 0);
this.addBodyPart(0, 1);
this.addBodyPart(1, 1);
this.setTail(); // sets this.tail to a pointer to the first element in the list
this.setHead(); // sets this.head to a pointer to the last element in the list
return this;
}
I think two different defer will be executed in reverse order. You’d make it more clear if you went:
defer {
this.setTail();
this.setHead();
}
Edit:
This is best for freeing resources:
const a = try initA();
defer a.deinit();
const b = try initB(a);
defer b.deinit();
Performing a.deinit() could invalidates b since it depends on a. Performing b.deinit(); after could go wrong. It’s best to perform b.deinit(); first and then a.deinit();.
I think the return value is already copied before the defer statements run.
You could add a scope that begins before the first defer and ends before the return so that the defer runs before the return.
But I don’t really understand why you are using defer at all.
const std = @import("std");
const builtin = @import("builtin");
const T = struct {
v: i31,
touched: bool = false,
pub fn finalize(self: *T) void {
std.debug.print("addr in finalize: {x}...", .{@intFromPtr(self)});
self.*.touched = true;
std.debug.print("finalized {any}\n", .{self.*});
}
};
fn fun(v: i31) T {
var t: T = .{ .v = v };
defer t.finalize();
std.debug.print("t in fun addr: {x} - t = {any}\n", .{ @intFromPtr(&t), t });
return t;
}
test "tst fun t" {
const t = fun(42);
std.debug.print("addr in tst: {x}...{any}", .{ @intFromPtr(&t), t });
try std.testing.expectEqual(true, t.touched);
}
pub fn main() !void {}
which shows that the defer self indeed is a different one, IIUIC, namely the local variable in the fun fn:
Test [1/1] main.test.tst fun t... t in fun addr: 7fff2023e1d0 - t = main.T{ .v = 42, .touched = false }
addr in finalize: 7fff2023e1d0...finalized main.T{ .v = 42, .touched = true }
addr in tst: 7fff2023e220...main.T{ .v = 42, .touched = false }expected true, found false
Test [1/1] main.test.tst fun t... FAIL (TestExpectedEqual)
(excuse the intermingled stderr output mess)
If I understood result location semantics correctly, the address should’ve been the same on all occasions, shouldn’t it?
If my understanding was wrong, it is still an easy reproduction.
NOTE: I tried to verify my idea with the language docs but couldn’t find the result location rules of a return. I suppose I got that part wrong. Instructive!
I meant that this should be/hold a reference to your data, not to use a reference to this instead. It doesn’t work because you’re still not returning &this (and you shouldn’t since it lives on the stack).