Completely ridiculous?

Is it completely absolutely ridiculous (or possible!) to write some wrappers for the builtins?

inline fn as(comptime T: type, value: anytype) T
{
    return @as(T, value);
}

It is more of a personal cometic nature…

I like the view of

const a: u4 = 42;
const b: u32 = as(u32, a);

more than

const a: u4 = 42;
const b: u32 = @as(u32, a);

I think it’s mostly a matter of preference, but my argument against it would be that I find it nice to know immediately that you have reached a minimal abstraction provided by the language, rather than seeing a function call that looks like there may be some value to looking at the definition of.

4 Likes

Many builtins have special rules. Try wrapping @field and report back after trying to replace @field(p, "y") = @field(p, "x") + 1; with wrappers.

The @builtin syntax lets the reader know that this is something different than regular function calls.

4 Likes

Yes true. It is mostly things like @as and @TypeOf, which are used quite frequently in my code which distract me visually :wink:

Another related question (I know so little).
IF I would do that for a few of these, is it possible to have this functions available in the whole project without explicit @import everywhere?

No, as far as I know there is no way to do that, I also think it isn’t wanted, because it would lead towards hard to understand code, where everyone has their own magically appearing utility functions (and everyone has different ones).

1 Like

true. i also like explicit actually…

I use this a lot:

inline fn cast(T: type, val: anytype) T {
    return @as(T, @intCast(val));
}

Doesn’t seem ridiculous to me. Makes arithmetic somewhat easier to read in fact.

2 Likes

The only thing is: it is impossible to make these global. You have to import them.

myzig.cast()

is making it less attractive again.

I guess you could create editor tooling that automatically creates a declaration for specific things in every file where you use it, so it would automatically add something like this:

const cast = @import("myutils").cast;
1 Like

Most non-trivial projects end up with a bucket for stuff used in many files, right? I call those common.zig.

So it’s just

const common = @import("common.zig");
const cast = common.cast;

Of course it would need to be pub inline fn, but this poses no problem.

The function itself is also three lines, so I’ll toss it at the bottom of a file as soon as I start casting. Maybe it gets moved if I need to use it in a lot of places.

I tried that, but still you have to import them in each file to use.
const cast = common.cast;

Zig is like this with everything.

I don’t think we’re going to get a builtin @asCast which is just @as(T, @intCast(v)), so yeah. Gotta import it.

Builtins are a big of a grab-bag, but mostly they’re things which userspace can’t do, which clearly, cast is not.

I could see an argument for it being std.math.cast though.

The funny thing is, that builtins seem impossible like @truncate.
We cannot give anytype as a result I believe.

1 Like

Correct, that’s an example of something which has to be a builtin. Neither @as nor @intCast can be implemented in user space. But the mere combination of the two clearly can be.

1 Like

Going back to the sanity of doing this for cosmetic reasons, it’s worth nothing that the standard library already does this with some simple functions like cos Zig Documentation. Up to you if that is more reasonable than @cos.

1 Like