I’d imagine the most common signature of the main function is
pub fn main() !void
Or, with the new Juicy Main:
pub fn main(init: std.process.Init) !void
For utilities that return a code to the shell/operating system, main would return a u8:
pub fn main() u8
With that in mind, I’m rewriting a program in Zig and it returns one of 3 values: 0 for success, 1 for connection error, and 2 for application error.
For example, this might look like this:
pub const success: u8 = 0;
pub const connection_error: u8 = 1;
pub const application_error: u8 = 2;
pub fn main() u8 {
return success;
}
Maybe we could tidy that up a bit by namespacing the result codes, like this:
pub const Result = struct {
pub const success: u8 = 0;
pub const connection_error: u8 = 1;
pub const application_error: u8 = 2;
}
pub fn main() u8 {
return Result.success;
}
What about, instead of returning a u8, we return an enum whose backing integer is a u8 and just cast that down to the u8?
pub const Result = enum(u8) {
.success = 0,
.connection_error = 1,
.application_error = 2,
};
pub fn main() Result {
return .success;
}
The changes in the standard library are fairly minimal. I tested this and it works fine:
diff --git a/lib/std/start.zig b/lib/std/start.zig
index e39465fe9b..8aebdf251d 100644
--- a/lib/std/start.zig
+++ b/lib/std/start.zig
@@ -731,10 +731,12 @@ inline fn callMain(args: std.process.Args.Vector, environ: std.process.Environ.B
inline fn wrapMain(result: anytype) u8 {
const ReturnType = @TypeOf(result);
- switch (ReturnType) {
- void => return 0,
- noreturn => unreachable,
- u8 => return result,
+ const ReturnTypeInfo = @typeInfo(ReturnType);
+ switch (ReturnTypeInfo) {
+ .void => return 0,
+ .noreturn => unreachable,
+ .int => |x| if (@TypeOf(x) == u8) return result else {},
+ .@"enum" => |x| if (x.tag_type == u8) return @intFromEnum(result) else {},
else => {},
}
if (@typeInfo(ReturnType) != .error_union) @compileError(bad_main_ret);
@@ -748,10 +750,13 @@ inline fn wrapMain(result: anytype) u8 {
return 1;
};
- return switch (@TypeOf(unwrapped_result)) {
- noreturn => unreachable,
- void => 0,
- u8 => unwrapped_result,
+ const UnwrappedResultType = @TypeOf(unwrapped_result);
+ const UnwrappedResultTypeInfo = @typeInfo(UnwrappedResultType);
+ return switch (UnwrappedResultTypeInfo) {
+ .noreturn => unreachable,
+ .void => 0,
+ .int => |x| if (@TypeOf(x) == u8) unwrapped_result else @compileError(bad_main_ret),
+ .@"enum" => |x| if (x.tag_type == u8) @intFromEnum(unwrapped_result) else @compileError(bad_main_ret),
else => @compileError(bad_main_ret),
};
}
This is something I’d personally like to have, but I wonder if it’s something that would be worthwhile for others, or if there’s a reason it’s not been done already (I don’t want to contribute unnecessary noise to the issue tracker, so I’m asking here
)?