This is supposed to be super simple code. Just open a file and write a line of text to it through the new writer interface. Yet I can’t get it to work.
const std = @import("std");
pub fn main() !void {
var output_file = try std.fs.createFileAbsolute("/home/cleong/Desktop/hello.txt", .{});
defer output_file.close();
var buffer: [4096]u8 = undefined;
var interface = output_file.writer(&buffer).interface;
try interface.print("This is a test\n", .{});
interface.flush() catch |err| {
_ = try output_file.write("Error?\n");
return err;
};
}
error: WriteFailed
/home/cleong/.zvm/0.15.2/lib/std/posix.zig:1376:22: 0x114800e in writev (std.zig)
.BADF => return error.NotOpenForWriting, // Can be a race condition.
^
/home/cleong/.zvm/0.15.2/lib/std/fs/File.zig:1760:21: 0x11445ba in drain (std.zig)
return error.WriteFailed;
^
/home/cleong/.zvm/0.15.2/lib/std/Io/Writer.zig:316:28: 0x1046a99 in defaultFlush (std.zig)
while (w.end != 0) _ = try drainFn(w, &.{""}, 1);
^
/home/cleong/.zvm/0.15.2/lib/std/Io/Writer.zig:310:5: 0x109f2e3 in flush (std.zig)
return w.vtable.flush(w);
^
/home/cleong/Desktop/cow.zig:17:9: 0x113d6fd in main (cow.zig)
return err;
The content of hello.txt contains the following afterward:
true. For some reason I thought it was already assigned) Need to be more careful when responding. One time when I didn’t compile program to verify its correct was the time it is incorrect
No the File.Writer still needs a var, otherwise it is a temporary which is const, even if interface was a method it would need a *File.Writer as self, the benefit of it being a method would be that you get a compile error. (which isn’t being done because other features are planned to make it a compile error)
But couldn’t the self of the method be *const File.Writer to make it work in that case? The method would just return a pointer to the interface, so having a *const as self would be legit I think. If the var is needed in the scope for other reasons then ok.
Then you would end up with *const Io.Writer, which you don’t want, you want both of them to be *T without const, they shouldn’t be const because they contain variables that will be mutated during the operations on the File.Writer and Io.Writer.
You don’t want *const File.Writer because then you don’t know whether you could reliably and safely get a non const pointer and you don’t want the File.Writer to be a const/temporary anyhow, because you don’t want the implementation methods of the interface which use @fieldParentPtr to get back to the *File.Writer to try and write to a constant/temporary instance (for example when updating the File.Writer.pos field), which would result in illegal behavior or segfaults.
But there are already countless topics about the Io.Reader/Writer interfaces and how they work, so I don’t really want to explain all of that again.