Continuing the discussion from Code review: initialization via tuple of tuples:
Zig has a type system the way C does (but much better designed): the focus is on defining how memory is used, and establishing how that memory gets into and out of functions. So it doesn’t need a ‘top’ type, like a type-of-all-types, because it doesn’t have a type hierarchy, just some useful rules for when the compiler allows you to coerce one type into another. anytype
doesn’t really function like a top type, it’s more of a placeholder: “any type can go here, stick something in this slot and see if the function compiles”. type
isn’t a top type either, that’s a specific tagged union called Type
, which exists at comptime and can be used accordingly. Zig’s type system is engineering, not mathematics.
But the type-of-no-types would be helpful, specifically so that @TypeOf(a, b)
could return a value when a
and b
have no type they mutually coerce to. This would just be a branch of the tagged union, Type.Bottom
would be traditional, but Type.NoType
would work just as well. The essence of what a bottom type is, is that it’s what the type system returns when a value can’t inhabit the type which is demanded by a statement.
It isn’t necessary that @TypeOf(a_u8_slice, a_bool)
throws an error, this just means that type reflection has to be careful about checking if a peer coercion is possible.
Because it isn’t even catchable:
test "bottom type" {
const a: []const u8 = "abcd";
const b: bool = true;
_ = @TypeOf(a, b) catch |e| {
std.debug.print("{!}", .{e});
};
}
This is just a compile error, making this kind of reflection very difficult.