Generics and functions

Taking GenericWriter as an example:

pub fn GenericWriter(
    comptime Context: type,
    comptime WriteError: type,
    comptime writeFn: fn (context: Context, bytes: []const u8) WriteError!usize,
) type {...

Is it possible to have something like this:

pub fn GenericStuff(
    comptime Context: type,
    comptime WriteError: type,
    comptime writeFn: fn (context: Context, bytes: []const u8),
    comptime writeFnOptional: ?fn (context: Context, bytes: []const u8) WriteError!usize,
) type {
...

Meaning that the second function would be optional?

(I guess this is not correct way…)

So, what would be the correct way to achieve what I’m trying to do?

What are you trying to do?

using an optional should work

2 Likes

You are right, ?fn does work.
I thought it would be too crazy to be true.

In case anyone has similar doubts, here’s a simple example of working code:

const std = @import("std");

pub fn fnCore(
    comptime Context: type,
    comptime action: fn (
        context: Context,
        value: u8,
    ) u8,
    comptime actionOption: ?fn (
        context: Context,
        value: u8,
    ) ?u8,
) type {
    return struct {
        context: Context,

        const Self = @This();

        pub inline fn act(
            self: Self,
            value: u8,
        ) u8 {
            return action(
                self.context,
                value,
            );
        }

        pub inline fn actOpt(
            self: Self,
            value: u8,
        ) ?u8 {
            if (actionOption != null) {
                const a = actionOption.?;
                return a(
                    self.context,
                    value,
                );
            } else {
                return null;
            }
        }
    };
}

pub const FnStuff = struct {
    two: u8 = 2,
    three: u8 = 3,
    const Self = @This();
    const FnCore = fnCore(
        *Self,
        calcDouble,
        null,
        // calcTriple,
    );
    pub fn calcDouble(
        self: *Self,
        val: u8,
    ) u8 {
        return self.two * val;
    }
    pub fn calcTriple(
        self: *Self,
        val: u8,
    ) ?u8 {
        return self.three * val;
    }
    pub fn calc(
        self: *Self,
    ) FnCore {
        return .{
            .context = self,
        };
    }
};

pub fn main() !void {
    var fn_stuff = FnStuff{};
    const stdout_file = std.io.getStdOut().writer();
    var bw = std.io.bufferedWriter(stdout_file);
    const stdout = bw.writer();

    const t2 = fn_stuff.calc().act(3);
    const t3 = fn_stuff.calc().actOpt(3);
    try stdout.print("2 * 3 = {d}\n", .{t2});
    try stdout.print("3 * 3 = {?}\n", .{t3});

    try bw.flush(); // don't forget to flush!
}
1 Like

These are shorter:

const a = actionOption orelse return null;
return a(self.context, value);
return if(actionOption) |a| a(self.context, value) else null;
4 Likes

My C background prevents me to accept that you can do such if and orelse statements :smiley:

1 Like