Skip to content

Proposal: Infer type on ranged for loops from the type of the range values instead of defaulting to usize #14704

Closed as not planned

Description

@BanchouBoo

Ranged loops defaulting to usize only makes sense when it's paired with a slice or array iteration, in any other case there isn't really any good reason for it that I can think of, especially when the values used aren't comptime_ints.

The following is the behavior I would expect from the types on ranged for loops:

// i is comptime_int, and thus won't work because this is a runtime loop
for (0..10) |i| {}

// i is a comptime_int, but works fine because the loop is inlined
inline for (0..10) |i| {}

// i is a u8
for (0..@as(u8, 100)) |i| {}

// i is a usize
for (slice, 0..) |item, i| {}

// i is a u16
for (@as(u8, 0)..@as(u16, 10000)) |i| {}

// i is a u8, since it's required for the start of the range to be a lower number than the end of the range it's guaranteed that i will not overflow
// if it's later decided that decrementing ranges will be allowed, then i should instead be a u16
for (@as(u16, 0)..@as(u8, 100) |i| {}

In discussion on this topic in the discord, the idea of putting the type on the capture was also floated:

for (0..10) |i: u32| {}

But I think basing it off the type of the values used in the range itself makes much more sense, personally.

There was also a suggestion to infer the integer type to the smallest type that will fit the range when using comptime_int to define the range.

// i is u4
for (0..10) |i| {}

But requiring an explicit type in there somewhere feels more "correct" to me, and I feel that the uses where you know both ends of the range at comptime and aren't iterating over an array or storing the number in a constant somewhere that can be give a type are pretty uncommon in practice.

Activity

  1. Srekel commented on Mar 20, 2023

    @Srekel

    Just to add my "+1", I just stumbled onto this issue in actual code, here was my workaround.

            for (0..3) |lod| {
                const lod_u4 = @intCast(u4, lod);
                world_patch_manager.WorldPatchManager.getLookupsFromRectangle(state.heightmap_patch_type_id, area_old, lod_u4, &lookups_old);

    The lod is a u4 because it doesn't need to be more. Since the for loop pretty clearly/explicitly fits inside a u4, I think it should work fine to just pass it in. Just like it does when you explicitly pass in, say, 3, you don't need to do @intCast(u4, 3).

    Code here (at the time of writing only 0..1 due to being WIP):
    https://github.com/Srekel/elvengroin-legacy/blob/main/src/systems/terrain_quad_tree.zig#L1257

  2. BanchouBoo commented on Apr 11, 2023

    @BanchouBoo
    ContributorAuthor

    Any chance we can get some elaboration on why this has been closed?

  3. andrewrk commented on Apr 11, 2023

    @andrewrk
    Member

    I'm not accepting language proposals at this time. I've already considered this and rejected it. If you tried to implement your proposal, you would see the problems with it. Unfortunately I don't have time to explain in detail why nearly all of the ~463 open proposals will be rejected.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions