Hello everyone!
I’ve just started to explore the language, and writing simple programs I’ve stumbled upon the writer interface copy issue. Now, I have this program in which even if I’m obtaining a pointer to the interface, the output is not the expected one.
const std = @import("std");
const StdOutHelper = struct {
buf: [1024]u8 = undefined,
stdout: std.fs.File = undefined,
writer: std.fs.File.Writer = undefined,
pub fn init() StdOutHelper {
var this = StdOutHelper {};
this.stdout = std.fs.File.stdout();
this.writer = this.stdout.writer(&this.buf);
return this;
}
pub fn getWriter(this: *StdOutHelper) *std.Io.Writer {
return &(this.writer.interface);
}
};
pub fn main() !void {
var stdout_helper = StdOutHelper.init();
var writer = stdout_helper.getWriter();
try writer.print("Hello world", .{});
try writer.flush();
}
Out: o world
instead of Hello world
Instead, I obtain the expected output if I create the writer in the getWriter
method:
const std = @import("std");
const StdOutHelper = struct {
buf: [1024]u8 = undefined,
stdout: std.fs.File = undefined,
writer: std.fs.File.Writer = undefined,
pub fn init() StdOutHelper {
var this = StdOutHelper {};
this.stdout = std.fs.File.stdout();
return this;
}
pub fn getWriter(this: *StdOutHelper) *std.Io.Writer {
this.writer = this.stdout.writer(&this.buf);
return &(this.writer.interface);
}
};
pub fn main() !void {
var stdout_helper = StdOutHelper.init();
var writer = stdout_helper.getWriter();
try writer.print("Hello world", .{});
try writer.flush();
}
Said so, I’m not understanding a lot:
- I’m creating a writer on the stack with a std library function, and I’m copying the whole struct as a field of the StdOutHelper, that lives on the stack too when created in the main function.
- I’m obtaining the interface to that copy in a second moment, and it’s not working as expected, so I must deduct that the whole writer struct is not copyable? Why if I copy it in the same function it starts to work?
- Which is the guideline to follow to understand when something is copyable or not? How can I understand if something is meant to “survive” the stack and it’s a copiable struct holding pointers to heap allocated stuff, or everything is meant to be consumed before the stack frame expiration?
I understand there is an ongoing process of designing the language, as a Zig newbie I’m struggling to understand if there is already some well defined pattern/guideline/direction in this sense.