How to protect a function against misuse at compile time

Suppose we have a struct with a feature that can be enabled or disabled based on some comptime parameter. A simple example looks like this:

const std = @import("std");                                                                                                                                                                                                                   

pub fn MyStruct(enableFeature: bool) type {
    return struct {
        const Self = @This();

        pub fn greet(self: *Self) void {
           _ = self;
           std.debug.print("Hello from {} instance\n", .{enableFeature});
        }

        pub fn useFeature(self: *Self) void {
            _ = self;
            if( enableFeature ) {
               std.debug.print("useFeature() success\n", .{});                                                                                                                                                                                
            } else {
               @panic("Feature not enabled");                                                                                                                                                                                                 
            }
        }
    };                                                                                                                                                                                                                                        
}

pub fn main() !void {
   var t_instance = MyStruct(true){};                                                                                                                                                                                                         
   var f_instance = MyStruct(false){};                                                                                                                                                                                                        
   t_instance.greet();                                                                                                                                                                                                                        
   t_instance.useFeature();
   f_instance.greet();                                                                                                                                                                                                                        
   f_instance.useFeature();
}

How do we improve this code by making useFeature() give a compile time error instead of a runtime error? My first instinct was to wrap useFeature() with if( enableFeature ) { } but this does not work.

After some experimentation, I found out that Zig does give us an elegant way to make useFeature() give a compile-time error when enableFeature == false! You can just replace @panic with @compileError(the solution is in spoiler text in case you want to try to figure it out on your own first).

Replace @panic with @compileError, note that this relies on enableFeature being known at comptime, which is the case here.But if it wasn’t, then you would always get a compile error.

I didn’t realise we were being secretive about this :stuck_out_tongue:

2 Likes

I personally would use:

comptime std.debug.assert(enableFeature);
4 Likes

pub fn MyStruct(comptime enableFeature: bool) type
You can have a better declaration of the comptime requirement for parameters in the function signature.

3 Likes