const std=@import("std");
pub fn main() !void {
var b_r = std.io.bufferedReader(std.io.getStdIn().reader());
var r = b_r.reader();
var count: u32 = 0;
var buf: [1000]u8 = undefined;
while (try r.readUntilDelimiterOrEof(&buf, '\n')) |line| {
std.debug.print("{s}\n", .{line});
count +=1;
}
}
All fine and dandy, until I try chaining calls:
const std=@import("std");
pub fn main() !void {
var r = std.io.bufferedReader(std.io.getStdIn().reader()).reader();
var count: u32 = 0;
var buf: [1000]u8 = undefined;
while (try r.readUntilDelimiterOrEof(&buf, '\n')) |line| {
std.debug.print("{s}\n", .{line});
count +=1;
}
}
which gets me a fat “cast discards const qualifier”. I don’t understand the error but I fixed it anyway with
var r = std.io.bufferedReader(std.io.getStdIn().reader()).unbuffered_reader;
Why a call to BufferedReader.reader() returns something that is not a reader?
Why is unbuffered_reader not a method?
But more importantly, why the first version works?
Doesn’t all of this violate the principle of least surprise?
The Reader is an interface. It requires you to provide a read method, and it turns that into a whole bunch of convenience methods. You could call the read method directly from the buffered reader, but it doesn’t make sense for the buffered reader to reimplement all of the convenience methods that come from Reader. There is a method to do unbuffered read from stdin.
unbuffered_reader is a member that holds the underlying reader that you passed in when constructing the object. std.io.bufferedReader(std.io.getStdIn().reader()).unbuffered_reader is basically equivalent to std.io.getStdIn().reader().
It has to be stored somewhere, and since there are no private member variables in zig, you can access it.
Just want to reiterate that this is the answer to why the first one works and why that is expected. The buffered reader is const if you don’t store it in a variable (it is temporary). When it’s const, you cannot call it’s reader() method. As soon as you have the var, that is no longer a problem and it works.