1. Figuring out if a value is comptime
pub inline fn comptimeKnown(val: anytype) bool {
const Tuple = @TypeOf(.{val});
return @typeInfo(Tuple).@"struct".field_attrs[0].@"comptime";
}
This one is pretty straightforward if you know how comptime fields work.
2. Figuring out if a value is comptime, part 2
comptime fields are being debated for removal. This absolutely devious workaround was posted by Fri3dNstuff, at https://codeberg.org/ziglang/zig/issues/32045#issuecomment-13664645.
pub inline fn comptimeKnown(x: anytype) bool {
const pair: struct { @TypeOf(x), usize } = .{ x, 0 };
return @TypeOf(" "[0..pair[1]]) == *const [0]u8;
}
How it works:
- A value must either be entirely
comptime-known or entirely runtime-known. A value iscomptime-knowniffit depends solely on othercomptimevalues. (Although note thatcomptime-ness gets lost at function call boundaries, which is why the one in the snippet isinline) - The literal 0 is always
comptimeknown. This means that the variableconst pair = .{ x, 0 }iscomptime-knowniffiffxiscomptime-known. - When slicing arrays using
array[start...end], if thestartandendare bothcomptimeknown, the type of the expression is a pointer to an array (*const [end-start]T). the type of the slicing expression is[]const T. - If
pairiscomptime-known (which, again, depends solely whetherxiscomptime-known),pair[1]is alsocomptime-known, so the slicing expression" "[0..pair[1]]has a pointer-to-array type. - Otherwise,
pair[1]is only runtime known, so the slicing expression" "[0..pair[1]]has a slice type.
3. Pseudo @ResultType
Proposal: `@Result` to match cast builtins inference API · Issue #16313 · ziglang/zig · GitHub may have been shot down, but you can still provide much of its proposed utility (in certain situations) via the magic of decl literals!
For example, in a pub fn Vector3(T: type) struct:
pub fn splat(n: T) @This() {
return .{ .x = n, .y = n, .z = n };
}
pub fn mul(self: @This(), factor: @This()) @This() {
return .{
.x = self.x * factor.x,
.y = self.y * factor.y,
.z = self.z * factor.z,
};
}
pub fn floatCast(vec: anytype) @This() {
return .{
.x = @floatCast(vec.x),
.y = @floatCast(vec.y),
.z = @floatCast(vec.z),
};
}
const foo: Vector3(f64) = ...;
const bar: Vector3(f32) = .mul(.floatCast(foo), .splat(1));
This leads to a kind of pseudo-Łukasiewicz notation I quite like.
4. std.array_hash_map
Not technically a language trick, but I wanted to include it anyways.
Are you tired of writing iterators like this?
var entries = hash_map.iter();
while (entries.next()) |entry| {
const key = entry.key_ptr;
const val = entry.value_ptr;
}
array_hash_map to the rescue! Since values are stored densely packed in a regular MultiArrayList, iterating becomes a breeze:
for (hash_map.keys(), hash_map.values()) |key, value| {}
It’s so nice! As an extra bonus, array_hash_map variants are Unmanaged by default.