Would it be possible for builtins like `@mod`

to be able to derive the limits of the integer type that is being cast into, similar to how the compiler understands bitshifting types must be log(T).

For example when i do this:

```
const whole: i32 = getBlackBoxNumber()
const remainder = @mod(whole, 8)
```

We know that remainder can only be a value between 0-7, and so it could easily be stored in a u8. Right now the compiler uses the same type as `whole`

. Meaning we get an i32 instead.

Obviously this would only work with comptime known values, but it *could* be a cool help/check, and I think is inline with decisions like bitshifting.

2 Likes

Compared to bitshift operators @mod also works with floating point numbers so it would be strange for it to work with one type but not with the other

1 Like

Huh. I never used modulus operator with a floating point number. I’ve always thought about it in the context of integer division.

There’s renewed interest in issue #3806, which would add ranged integer types to Zig.

When (if but hopefully when) that lands, constraining the result of `@mod`

to a range is simple if the modulus is comptime-known:

```
const remainder: @Int(0, 16) = @mod(some_val, 17);
```

That’s using the convention I consider proper, where a range is expressed inclusive of both values, so `[start, end]`

not `[start, end)`

as we do for e.g. slicing (but not for switch prongs).

Expressing the range of a modulus operation is actually a case for using the `[start, end)`

convention, but it’s the only one IMHO. Which would you rather work with:

```
const WeekDay: type = @Int(1, 7);
// or...
const WeekDay: type = @Int(1, 8);
```

It’s really only when a range is anchored at zero that expressing it exclusive of its highest value is convenient, and the whole point of ranged integers is to get away from that requirement.

1 Like

Y’know what? I changed my mind, modulus is an *excellent* argument for using inclusive ranges.

Consider (this is math not Zig):

```
[0, n-1] = a % n where n ∈ ℕ
```

`[0, -1]`

is not a valid range (it can be used as a notation for a range-of-nothing but that’s technically math abuse), and `a % 0`

is also invalid. So the equation doesn’t hold for `0`

since the left term is impossible.

The alternative (math again):

```
[0, n) = a % n where n > 0
```

As it happens `[0, 0)`

is the not-math-abuse way of representing an empty range, and this is one of the reasons why as programmers we like semi-open intervals. But that’s why we have to specify that `n`

is positive: `a % 0`

is an impossibility that isn’t equal to the empty interval.

It makes sense for Zig to treat an integer type with a range including no integers as a type error, and dividing or `@mod`

by 0 is illegal behavior. So this is in fact an argument for closed interval / inclusive ranges.

2 Likes