Previously I used writeStreamingAll, which worked fine, but I needed a function that also formatted.
I’d be really grateful for any help regarding this error
Can someone please explain why using a copy of stdout.interface makes a difference to using a reference to stdout.interface? Even if it is a copy, shouldn’t it be a shallow copy, and any copied internal references should still point to the original valid memory locations?
This is what I would consider a footgun: the code compiles and maybe appears to work (doesn’t crash when omitting writer.flush), but then crashes. It also violates what I recall (or maybe just imagine) being one of the Zig philosophies: the simplest way should be the correct way (using stdout.interface is simpler than &stdout.interface). Is there a way to write this code such that the incorrect way is a compile error?
seg.zig:7:9: error: local variable is never mutated
var stdout = std.Io.File.stdout().writer(io, &buf);
^~~~~~
seg.zig:7:9: note: consider using 'const'
seg.zig:9:15: error: expected type '*Io.Writer', found '*const Io.Writer'
try writer.print("hi {}\n", .{2});
~~~~~~^~~~~~
seg.zig:9:15: note: cast discards const qualifier
So maybe the compiler does try to nudge me in the correct direction, but instead of shuffling around const and var until it compiles, I didn’t see that I needed to add &.
Notice how there is not a pointer to implementation state.
Instead, implementations use @fieldParentPtr to convert a *Reader/*Writer, which is assumed to be a pointer to a field (you specify by name) in the implementation type.
By making, and using, a copy of the Reader/Writer field, you are breaking that assumption. But that assumption is currently can’t be verified, so the code just continues assuming it is correct, and treating the memory around the copy as though it is the implementation type when it is not, this is illegal behaviour, anything could happen e.g. operating on a different file you opened in an entirely different part of your program!!!.
Sure, but they require language changes in one of the following directions
a generic/trait/etc system that makes this a non issue
pinned types, have issues with zigs existing type system and memory model
pinned places, solves issues of pinned types, but has a pretty damning issue that I can’t remember atm.
borrow checker/lifetimes, drastically increases language and compiler complexity, slows compile times, false positives restrict possible code, false negatives defeat the point unless it is good enough.
other things I can’t think of.
I am infavour of changing the language to make this a compile error, but I dont have a solution to actually do that without contradicting zigs ideals.
The compile error is specifically about incorrect const because the Reader/Writer data needs to be mutated, whether it’s a copy or not; you need a var regardless, and with it, you get the unchecked illegal behaviour I described earlier.