Generic Types

Generic functions are fun, let’s try generic data types next!

We’ll create a type that limits values to a certain range. It should work for any number type.

const std = @import("std");
const print = std.debug.print;

const LimitError = error{
    OutOfRange,
};

// Limited is a function that returns a type.
fn Limited(T: type, min: T, max: T) type {
    return struct {
        // @This is the type we’re currently defining.
        const Self = @This();
        value: T,

        fn init(value: T) !Self {
            var r: Self = undefined;
            try r.set(value);
            return r;
        }

        fn get(self: Self) T {
            return self.value;
        }

        fn set(self: *Self, value: T) !void {
            if (value < min or value > max)
                return LimitError.OutOfRange;
            self.value = value;
        }
    };
}

pub fn main() !void {
    var l = try Limited(u64, 0, 100).init(5);
    print("l is a {s}\n", .{@typeName(@TypeOf(l))});
    print("l is {}\n", .{l.get()});
    try l.set(50);
    print("l is {}\n", .{l.get()});
    l.set(500) catch {
        print("got error!\n", .{});
    };
}
$ zig run limited.zig
l is a limited.Limited(u64,0,100)
l is 5
l is 50
got error!

Next example: Reflection.