Memory and returning struct from function?

When I return a struct from a function, is this undefined behavior? because the local var for the struct will be stack based? It has been working so far, but now I try to understand what is happening there with the memory.

pub const Tile = struct {
    x: f32,
    y: f32,
    w: f32,
    h: f32,
};

pub fn new(x: f32, y: f32, w: f32, h: f32) Tile {
    return Tile{
        .x = x,
        .y = y,
        .w = w,
        .h = h,
    };
}

[edit] and here is an example showing how I use this. In fact I end up returning another struct containing that struct:

const std = @import("std");

const js = @import("../js.zig");
const tiles = @import("../tiles.zig");

const black = "#000000";
const white = "#FFFFFF";
const daft = [_]u8{0} ** 8;

pub fn new(ctx: js.Context2D, tile: tiles.Tile) Renderer {
    var size = tile.w / 8.0;

    //clear frame
    ctx.fillStyle(black);
    ctx.strokeStyle(white);
    ctx.lineWidth(1);
    ctx.strokeRect(tile.x, tile.y, tile.w, tile.h);
    ctx.fillRect(tile.x, tile.y, tile.w, tile.h);

    return Renderer{
        .tile = tile,
        .size = size,
    };
}

pub const Renderer = struct {
    tile: tiles.Tile,
    size: f32,

    pub fn drawFrame(self: Renderer, ctx: js.Context2D, frame: u32, frameMS: u32) void {
        for (daft) |_, x| {
            for (daft) |_, y| {
                const xf32 = @intToFloat(f32, x);
                const yf32 = @intToFloat(f32, y);
                if ((x % 2 == 0 and y % 2 == 0) or (x % 2 != 0 and y % 2 != 0)) {
                    ctx.fillStyle("#000000");
                } else {
                    ctx.fillStyle("#FFFFFF");
                }
                ctx.fillRect(self.tile.x + (xf32 * self.size), self.tile.y + (yf32 * self.size), self.size, self.size);
            }
        }
    }
};

I took a brief glance and it should all be good, because I don’t see you returning any pointers. So the stack based values will be copied into the struct that is returned.
Or are you seeing unexpected results? In that case I have too look harder.

1 Like

As far as I understand things (but I could very well be wrong!), (1) indeed this is defined behavior, because the returned value is copied back to the caller; and (2) there is a implementation optimization (RLS = result location semantics) that skips that step, and instead return directly writes to the result location, e.g. in the caller’s stack frame.

See e.g. https://github.com/ziglang/zig/issues/2809 .

1 Like

Thanks both. Yes it is working, but I was suspicious why, since I expected stack based allocations to become invalid. RLS looks very interesting! and looking forward to more documentation around these features :slight_smile: since I realised I can use that also for stack based array allocations, which caught me out earlier. (although I was only returning a slice onto it, but now I can fix that too). Thanks for your patience.