I want const a: u32 = worker.group * 64 + worker.local_rank to work wether worker uses u8 or u32 internally.
const Animal = type{ Dog, Cat }; // like error unions, but for types
But I’d have two more in reality.
I want infer. Like this:
fn function(generic_param: infer T) ReturnType {
...
}
Instead of this:
fn function(comptime T: type, generic_param: T) ResultType {
...
}
Or this:
fn function(generic_param: anytype) ResultType {
const T = @TypeOf(generic_param);
...
}
It has the potential for some amount of type matching, with arything that’s a structural type:
fn function(generic_ptr: *infer T) ResultType {
...
}
And also using result type location for userland functions:
fn function(arg: Arg) infer T {
switch (@typeInfo(T)) {
...
}
...
}
I would wish for ways to add constraints to anytype or comptime T: type that are standardized and composable.
Current conventions mostly use comptime, but there still doesn’t seem to be a consensus for applying type constraints to generics.
Lots of languages have a notion of type classes, and it’s a pattern I happen to enjoy using where applicable. Whether this belongs for a language like zig is debated, and some argue it could exist via library code.
I don’t know what the solution is, but I do think there is complexity in getting type errors from comptime type checks that you have to go read and understand in context.
So… a union(enum)?
Yes but as with anytype you wouldn’t need to switch over the type (so basically a named and type-restricted anytype).
I think they mean assigning an ID to every type akin to how every error.ErrorTypeis assigned a u64 value. However, this only works for error unions by keeping a global set defined strictly by name. Types have a name and a scope, so in order to keep a global scope you’d have to use a types fully qualified name. Maybe with the dot notation this could exist?
Isn’t what the compiler already does? I mean, all types are unique from the compiler’s perspective and the compiler knows what the full type name is, so they could be indexed as well, no?
For casting to feel less painful. There has to be a way.
I don’t understand why we don’t have a generic @cast(comptime T: type, expression) built-in for . Is it really that much of a footgun?
Yes, it is a footgun. If Zig did that, then it would buy into the whole C model where the single cast operator is actually overloaded to do very different things based on what the input and output types are. That overloading is exactly what the different builtins in Zig are trying to avoid.
Using value: Type instead of @as(T, value) would be another wish of mine. But replacing casting altogether with one builtin would be problematic imo. It does very different things for different types, it introduces differert illegal behavior.
I forgot to specify I was talking about numeric conversion only. So casting between different sized floats and integers. I can understand why pointer, const and bitcasting are separate.
So yeah, an overloaded cast for anything that’s semantically a number would be my wish.
macro system
the reason why there are multiple kinds of casts for anything is because they have different behaviour/semantics!!! in a few cases there is only one option, but what about the cases where there are multiple? how would you differentiate them if it was just a single @cast builtin.
Enforcing the tag of a union to be comptime known:
const MyTypeGroup = union(comptime enum) {
foo: Foo,
bar: Bar,
};
fn (a: MyTypeGroup) void {
// this is resolved at compile time
switch(a) {
...
}
}
The full C99 designated-init feature set for struct initialization, everything else I can live with ![]()
It’s definitely arguable though whether a single one-for-all cast is any worse than C++ style granular casts. E.g. a cast is forcing a different ‘view’ on a specific piece of data, and that is always a potential footgun (if it wasn’t, no cast would be needed).
IMHO when casts actually require some ‘runtime actions’ (e.g. converting a float into an int, like 1.4 => 1) this shouldn’t be called a cast but a ‘conversion’. E.g. ‘cast’ should be reserved for assigning a different ‘type system view’ to the same bag of bits, and this always resolves to a ‘runtime nop’. This is IMHO the only area where C casts are ambigious, but I can see why they didn’t go for a bitcast when converting between float and int, that would definitely be confusing.
What’s missing in zig for that? (I admit I did not look at the standard, but zig already does many struct init that C does).
const x: i16 = 42.5;
const y: f32 = @cast(x);
y == ?
Should @cast be equivalent to @floor, @trunc, @round, or @ceil? @intFromFloat previously truncated, but I don’t see why that should be preferred over any of the others.
I’d love to be able to do something like this :
const std = @import("std");
pub fn main() !void {
var data: [1024]u32 = undefined;
@memset(&data, 1);
// I would love if this lowers to the while
// loop
var i: usize = 0;
var sum: u64 = 0;
for (data[0..1024 :8]) |u| { // f would be @Vector(8, u32)
sum += @reduce(.Add, u);
}
std.debug.print("{d}", .{sum});
// to this :)
i = 0;
sum = 0;
while (i + 8 < data.len) : (i += 8) {
const my_vec: @Vector(8, u32) = data[i..][0..8].*;
sum += @reduce(.Add, my_vec);
}
while (i < data.len) : (i += 1) {
sum += data[i];
}
std.debug.print("{d}", .{sum});
}
Basically the ability to add a step [from..to:step] I think this would make writing simd code very easy, and it would make handling multi dimensional data quite nice too.