# Explicit Casts

### Explicit Casts

Zig does not perform most numeric conversions automatically.

This is intentional. Conversions can lose information, change sign, truncate values, or change precision. Zig requires the programmer to write conversions explicitly.

Consider:

```zig
const a: i32 = 10;
const b: u32 = 20;

const c = a + b; // error
```

The types differ. Zig does not guess which conversion is correct.

You must convert one value explicitly.

```zig
const a: i32 = 10;
const b: u32 = 20;

const c = a + @as(i32, @intCast(b));
```

This conversion has two parts.

```zig
@intCast(b)
```

This converts the integer value.

```zig
@as(i32, ...)
```

This supplies the destination type.

The compiler checks whether the conversion is valid.

If the value cannot fit, the program traps in safe modes.

```zig
const big: u32 = 1000;
const small: u8 = @intCast(big); // trap in safe mode
```

`1000` does not fit in `u8`.

An integer may be converted to a floating-point value.

```zig
const n: i32 = 10;

const x = @as(f64, @floatFromInt(n));
```

`x` is an `f64` with value `10.0`.

A floating-point value may be converted to an integer.

```zig
const x: f64 = 3.75;

const n: i32 = @intFromFloat(x);
```

The fractional part is discarded.

Here `n` becomes `3`.

The conversion must still fit in the destination type.

```zig
const x: f64 = 1000.0;

const n: u8 = @intFromFloat(x); // trap in safe mode
```

A value may also be converted between floating-point types.

```zig
const x: f64 = 3.141592653589793;
const y: f32 = @floatCast(x);
```

The result may lose precision because `f32` has fewer bits.

Sometimes the destination type is already known from context.

```zig
const x: f32 = @floatCast(3.14);
```

The compiler sees that the result must be `f32`.

When the context is not enough, use `@as`.

```zig
const x = @as(f32, @floatCast(3.14));
```

Pointers also require explicit conversions.

```zig
const std = @import("std");

pub fn main() void {
    var x: i32 = 10;

    const p: *i32 = &x;

    std.debug.print("{d}\n", .{p.*});
}
```

A pointer conversion is not an integer conversion. Zig separates these operations clearly.

Bit-level reinterpretation uses different operations than numeric conversion.

```zig
const bits: u32 = 0x40490fdb;

const pi: f32 = @bitCast(bits);
```

`@bitCast` does not change the bits. It reinterprets them as another type of the same size.

This differs from numeric conversion.

```zig
const pi: f32 = @floatFromInt(bits); // numeric conversion
```

The two operations mean completely different things.

Integer widening is usually safe.

```zig
const small: u8 = 100;
const big: u32 = small;
```

The value fits naturally.

Integer narrowing requires an explicit cast.

```zig
const big: u32 = 100;
const small: u8 = @intCast(big);
```

This prevents accidental truncation.

Explicit casts make conversions visible. When a reader sees a cast, they immediately know the code is crossing a type boundary.

Use casts carefully. Most unnecessary casts are a sign that the types should be designed more clearly.

Exercises:

1. Convert a `u8` value to `u32`.

2. Convert an `i32` to `f64` and print the result.

3. Convert `7.9` to an integer and print the result.

4. Attempt to cast `300` into `u8` and observe the behavior in a safe build.

5. Use `@bitCast` to reinterpret a `u32` value as `f32`.

