@as(f32, value) expects f32?

zig version: 0.12.0-dev.1808+69195d0cd

I am unsure what is going on here:
Using raylib, and trying to get the letterbox example to run

‘c.GetScreen*()’ returns a c_int
‘VIRT_SCRN_*’ is a c_int
‘scale’ is also a c_int from @divFloor()

const mouse_x: c_int = -(c.GetScreenWidth() - (VIRT_SCRN_WIDTH * scale));
const mouse_y: c_int = -(c.GetScreenHeight() - (VIRT_SCRN_HEIGHT * scale));

const float_mouse_x: f32 = @as(f32, mouse_x) * 0.5;
const float_mouse_y: f32 = @as(f32, mouse_y) * 0.5;

Returns error expected type f32:

src/main.zig:52:45: error: expected type 'f32', found 'c_int'
        const float_mouse_x: f32 = @as(f32, mouse_x) * 0.5;

But this works just fine:

const mouse_x: c_int = 1;
const mouse_y: c_int = 1;
const float_mouse_x: f32 = @as(f32, mouse_x) * 0.5;
const float_mouse_y: f32 = @as(f32, mouse_y) * 0.5;

What are the actual values of mouse_x and mouse_y?
In zig c_int will always be the same size as an int would be in C for whatever system you are compiling for. However in C types do not have a guaranteed size, so the c_int my be bigger than the f32 size which would cause it not to cast. Then when you put the type signature for float_mouse it expects a f32, but since the cast of mouse_x fails it is still read as a c_int and there is a type mismatch. So this could be the issue.

They should be x = -800, y = -450, since I’m not doing the scaling properly, which is the window width/height negated. Doing the scaling properly would look like:

        const scale = @min(
            (@as(f32, c.GetScreenWidth()) / @as(f32, VIRT_SCRN_WIDTH)),
            (@as(f32, c.GetScreenHeight()) / @as(f32, VIRT_SCRN_HEIGHT)),
        );

Which returns the same error. Except now at the new @as(f32, value)s
The Virt width/height is 640, 480 btw

Instead of @as(f32, value) use @as(f32, @floatFromInt(value)) @as is just to tell what the type is supposed to be, but you still have to explicitly say that you want to cast your int value to a float value.

6 Likes

Ah that did it. Thank you

1 Like

Hi! I use Zig for image processing stuff, and I have to deal with a lot of casting.
I was typing @as(f32, @floatFromInt(val)) too often, so I made a small as function that you can use like: as(f32, val).

Here it is, hopefully it will be useful to someone.

/// Converts between numeric types: .Enum, .Int and .Float.
pub inline fn as(comptime T: type, from: anytype) T {
    switch (@typeInfo(@TypeOf(from))) {
        .Enum => {
            switch (@typeInfo(T)) {
                .Int => return @intFromEnum(from),
                else => @compileError(@typeName(@TypeOf(from)) ++ " can't be converted to " ++ @typeName(T)),
            }
        },
        .Int => {
            switch (@typeInfo(T)) {
                .Enum => return @enumFromInt(from),
                .Int => return @intCast(from),
                .Float => return @floatFromInt(from),
                else => @compileError(@typeName(@TypeOf(from)) ++ " can't be converted to " ++ @typeName(T)),
            }
        },
        .Float => {
            switch (@typeInfo(T)) {
                .Float => return @floatCast(from),
                .Int => return @intFromFloat(from),
                else => @compileError(@typeName(@TypeOf(from)) ++ " can't be converted to " ++ @typeName(T)),
            }
        },
        else => @compileError(@typeName(@TypeOf(from) ++ " is not supported.")),
    }
}

And this makes me think about the recent commit that tells inline is redundant in a comptime context. Isn’t comptime also redundant for variables of type type?

4 Likes