Help with correct use of random?

I started on a small helper for my random numbers in WASM (since I seed it from a call to javascript) I ended up with:

const std = @import("std");
const rand = std.rand;

var rnd: std.rand.Xoroshiro128 = undefined;

pub fn init(seed: u32) void {
    rnd = rand.DefaultPrng.init(seed);
}

pub fn next() f32 {
    return rnd.random.float(f32);
}

pub fn zeroUntilU8(until: u8) u8 {
    return @floatToInt(u8, rnd.random.float(f32) * @intToFloat(f32, until));
}

This works fine. However, trying to be clever I changed it to this:

const std = @import("std");
const rand = std.rand;

var rnd: std.rand.Random = undefined;

pub fn init(seed: u32) void {
    rnd = rand.DefaultPrng.init(seed).random;
}

pub fn next() f32 {
    return rnd.float(f32);
}

pub fn zeroUntilU8(until: u8) u8 {
    return @floatToInt(u8, rnd.float(f32) * @intToFloat(f32, until));
}

It took me a while to realise this was the change that was corrupting memory behind a container level var array elsewhere in my code base. It is still not obvious to me why this is the case? Is there any compiler options that would have helped me spot this? I can only assume that since I dont hold a ‘reference’ to the Xoroshiro128 itself, that some state is lost allowing the memory corruption?

zig 0.8.1

Unfortunately I don’t know of a way to catch this. Do note that the interface to Random has recently changed, but I’m not sure if it would have helped you here.

It seems that to use Random and other things in std correctly, you need to be aware of some of the conventions used, such as how inheritance is implemented. In order to use a “child type”, it’s memory must outlive any references to it’s parent type that have been extracted. In this case, the memory for DefaultPrng must outlive any reference to the “Random” parent type. Short of a “borrow checker” like Rust, I’m not sure how Zig could catch this.

Thanks for the insights, I think this is also what just caught me out trying to implement my own ‘parent type’, which is a shame since I am now having to hold extra child references when I am only dealing with the parent type.