Does it make sense to create a function that takes a stdout writer which might not be used?

Hey,

I’m new to zig & low level programming and since I’ve seen https://viewsourcecode.org/snaptoken/kilo/ being mentioned here couple of times, I decided to have a look as well and try to implement it in zig.

Step 30 implements a function that uses either ioctl to get the row and column counts, or if that fails it tries to get the counts by writing escape sequences to stdout and then doing couple of more steps that are not important to this example.

int getWindowSize(int *rows, int *cols) {
  struct winsize ws;
  if (1 || ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == -1 || ws.ws_col == 0) {
    if (write(STDOUT_FILENO, "\x1b[999C\x1b[999B", 12) != 12) return -1;
    editorReadKey();
    return -1;
  } else {
    *cols = ws.ws_col;
    *rows = ws.ws_row;
    return 0;
  }
}

My attempt to recreate the function in zig:

pub fn getWindowSize(stdout: *std.Io.Writer) !void {
    _ = stdout;
    var winsize: std.posix.winsize = .{
        .row = 0,
        .col = 0,
        .xpixel = 0,
        .ypixel = 0,
    };
    const err = std.posix.system.ioctl(
        std.posix.STDOUT_FILENO,
        std.posix.T.IOCGWINSZ,
        @intFromPtr(&winsize),
    );
    if (std.posix.errno(err) == .SUCCESS) {
        EDITOR_CONFIG.screen_rows = winsize.row;
        EDITOR_CONFIG.screen_cols = winsize.col;
    } else {
        // TODO
        @panic("write escape sequences to stdout");
    }
}

Should there be a function that takes a stdout writer when there is a possibility that the function will not do any IO? I guess the same question applies to a function taking an allocator that in some cases might not do any allocations. From what I’ve understood the good thing about having an allocator or Io as a parameter of a function is that it makes it clear that the function allocates or does IO.

One idea that came to my mind was to have two funcs:

pub fn getWindowSize() !void

and

pub fn getWindowSizeFallback(stdout: *std.Io.Writer) !void

and then do

getWindowSize() catch {
    try getWindowSizeFallback(stdout);
};

But this looks little bit weird to me.

Maybe I’m just really overcomplicating a small simple thing, but what would be a zig way of doing this?

yes, and often neither is guaranteed. I don’t see why you’d be more strict with writer/readers?

Nothing wrong with this either! I’d do that only if its inconsistent if the caller falls back or not.

1 Like

Ah, alright so I’m just overcomplicating it. Will have to read a lot more zig code.
Thanks!