#How do I declare complex types like a stdout buffered writer?

1 messages · Page 1 of 1 (latest)

sour torrent
#

For example, this works fine:

const stdout_file = std.io.getStdOut().writer();
var stdout_bw = std.io.bufferedWriter(stdout_file);
const stdout = stdout_bw.writer();

but I cannot figure out how I'm supposed to write the type of any of those variables if I wanted to pass them to a function or store them in a struct anywhere. The best I can do for now is copy and paste those lines into every function that needs stdout, and none of them seem terribly expensive so it generally works fine, but if I need to flush in a different function than the one I'm writing in, it's not going to work

supple river
#

A simple (enough) way is to make a temporary zig file with the following :

const std = @import("std");
const writer = @import("std").io.getStdOut(). writer();

pub fn main() !void {
    std.debug.print("{any}\n", .{@typeOf(writer)});
}```
#

Then it will tell you what the type is.

So, per example the result might be std.io.writer then in your function you would do :

fn myFunc(wrt : std.io.writer) !void {
    try wrt.print("Hello, World!\n", .{});
}
sour torrent
#
std.debug.print("{any}\n", .{@TypeOf(stdout)});
std.debug.print("{any}\n", .{@TypeOf(stdout_bw)});
io.GenericWriter(*io.buffered_writer.BufferedWriter(4096,io.GenericWriter(fs.File,error{NoSpaceLeft,DiskQuota,FileTooBig,InputOutput,DeviceBusy,InvalidArgument,AccessDenied,BrokenPipe,SystemResources,OperationAborted,NotOpenForWriting,LockViolation,WouldBlock,ConnectionResetByPeer,ProcessNotFound,NoDevice,Unexpected},(function 'write'))),error{NoSpaceLeft,DiskQuota,FileTooBig,InputOutput,DeviceBusy,InvalidArgument,AccessDenied,BrokenPipe,SystemResources,OperationAborted,NotOpenForWriting,LockViolation,WouldBlock,ConnectionResetByPeer,ProcessNotFound,NoDevice,Unexpected},(function 'write'))
io.buffered_writer.BufferedWriter(4096,io.GenericWriter(fs.File,error{NoSpaceLeft,DiskQuota,FileTooBig,InputOutput,DeviceBusy,InvalidArgument,AccessDenied,BrokenPipe,SystemResources,OperationAborted,NotOpenForWriting,LockViolation,WouldBlock,ConnectionResetByPeer,ProcessNotFound,NoDevice,Unexpected},(function 'write')))

that kinda highlights the problem decat

crisp moon
#

When passing to a function, take anytype

#

That'll allow other writers as well then

#

When storing, you'll either have to
(a) use the AnyWriter interface (be careful to not propagate anyerror), or
(b) make your type generic. If you make the type generic, then you'd pass like @TypeOf(stdout) as the type paramter or have the function take the stdout itself with anytype and then use @TypeOf itself

#

But generally I wouldn't store a writer and instead have the user pass it when it's needed

supple river
#

Or my help wasn't helpful I mean

sour torrent
#

currently i'm just thinking of the case of something like a REPL or a text adventure game where it really is specific to stdout and stdin and doesnt really make sense to be generic over other writers to files or network streams or anything like that
AnyWriter would work if i was just working with stdout directly but doesnt seem to work for the bufwriter

#

ideally id like to bundle all my stdout and stdin stuff in a context struct or just store them globally but im not sure how to achieve that

crisp moon
#

You can get the AnyWriter interface from any writer with .any()

#

I still think you should just pass it. If you really only pass stdout, then anytype will have worked the same as if you had made it the concrete type, since only one function will get generated

#

If you really still wanna store it, I'd probably use AnyWriter. Just make sure to shrink the error set down, like

fn Meow(out: std.io.AnyWriter) !void {
    out.writeAll("Meow!\n") catch return error.WriteError;
}```
sour torrent
#

in the worst case scenario i just dont want to be calling functions like doSomething(allocator, stdout, stdout_bw, stdin, stdin_br, actual_arg, actual_arg2)
i'm sure that worst case can be avoided but it still just seems like a mess if i cant bundle my stdio stuff

#

idk maybe i just write my own functions like std.debug.print for reading and writing and skip the buffering

#

it just seems like a non solution and i can imagine it not working out if i actually needed buffering in the case of file IO in a streaming parser

crisp moon
#

I'm still curious why AnyWriter "doesn't seem to work" for buffered writers. They work just fine.

sour torrent
#

if you mean std.io.bufferedWriter(fd).writer().any() then yeah but it loses the buffered api like .flush() so i still have to pass the bw separately

#

maybe i'm just overcomplicating things but if the zig motto is that its designed for "robust, optimal and reusable" software, encourages "optimal" software by not providing a "non optimal" built in stdout print but makes it a pain in the ass to write an "optimal" one then idk zinguslover72

#

i appreciate the suggestions though, it doesnt sound like theres really anything not yet mentioned so i'll see what i can do with that
god help me if i need to pass file bufreaders in the future

crisp moon
#

If you really want to store it so bad you could do like this lol

fn Context(
    Writer_Impl: type,
    Reader_Impl: type,
) type {
    return struct {
        writer_impl: Writer_Impl,
        writer: @TypeOf(@as(Writer_Impl, undefined).writer()),
        reader_impl: Reader_Impl,
        reader: @TypeOf(@as(Reader_Impl, undefined).reader()),
    };
}

fn Make_Context(
    writer_impl: anytype,
    reader_impl: anytype,
) Context(@TypeOf(writer_impl), @TypeOf(reader_impl)) {
    return .{
        .writer_impl = writer_impl,
        .writer = writer_impl.writer(),
        .reader_impl = reader_impl,
        .reader = reader_impl.reader(),
    };
}

// usage
const stdout_file = std.io.getStdOut();
const stdin_file = std.io.getStdIn();
var stdout_bw = std.io.bufferedWriter(stdout_file.writer());
var stdin_bw = std.io.bufferedReader(stdin_file.reader());
const ctx = Make_Context(&stdout_bw, &stdin_bw);```
sour torrent
#

i'm not entirely sure i understand how this works but its interesting if it does dorimecheems

crisp moon
#

@sour torrent If you're interested in updating to master, this has been simplified a lot

#

std.Io.Writer and std.Io.Reader are now non-generic, store the buffer in the interface, and have the flush function

sour torrent
#

interesting, I’ll check that out

crisp moon
#

So it'd look like

const Context = struct {
    out: *std.Io.Writer,
    in: *std.Io.Reader,
    ally: std.mem.Allocator,
};

// usage
var stdin_buf: [2048]u8 = undefined;
var stdin_reader = std.fs.File.stdin().reader(&stdin_buf);

var stdout_buf: [2048]u8 = undefined;
var stdout_writer = std.fs.File.stdout().writer(&stdout_buf);

const ctx: Context = .{
    .out = &stdout_writer.interface,
    .in = &stdin_reader.interface,
    .ally = std.heap.smp_allocator,
};```