Skip to content

Loop Syntax with Range, Step, and Reverse Support #5

@iso2t

Description

@iso2t

• Proposal: 20250806-loop-range
• Authors: Wylan Shoemaker
• Status: Draft
• Discussion: (link to GitHub PR or thread)

Summary

This RFC proposes the introduction of a new loop construct in Loom that supports:
• Iteration over numeric ranges using .. and ..=
• Optional step value for custom increments/decrements
• An optional rev prefix for reversed iteration

The goal is to create a more readable, modern alternative to C-style loops, while also providing powerful, safe iteration over integers and floats.

Motivation

The current looping mechanisms in most languages either:
• Require verbose, error-prone syntax (for (;;)),
• Or are overly restrictive when it comes to range flexibility.

We want to design a looping construct that:
• Reads naturally and clearly,
• Supports both inclusive/exclusive ranges,
• Works for both integers and floats (with explicit step for the latter),
• Allows reverse iteration in a clean and intuitive way,
• Can eventually extend to support pattern destructuring and custom iterators.

This will make Loom more expressive and accessible, particularly for mathematical or data-centric code.

Guide-Level Explanation

Basic Syntax

loop (i in 0..5) {
    print(i); // 0, 1, 2, 3, 4
}

loop (i in 0..=5) {
    print(i); // 0, 1, 2, 3, 4, 5
} 

With Step

loop (i in 0..10 step 2) {
    print(i); // 0, 2, 4, 6, 8
} 

Reversed Loop

rev loop (i in 0..5) {
    print(i); // 4, 3, 2, 1, 0
}

Float Ranges

loop (f in 0.0..1.0 step 0.2) {
    print(f); // 0.0, 0.2, 0.4, 0.6, 0.8
} 
    • step is required for floating-point ranges.

Edge Cases
Case Behavior
loop (i in 5..5) 0 iterations
loop (i in 5..5 step 1) 0 iterations
loop (i in 5..0) Infinite loop (unless step)
loop (f in 0.0..1.0) Compile-time error (no step)

Reference-Level Explanation

Grammar Changes

LoopStmt   ::= [ 'rev' ] 'loop' '(' Pattern 'in' RangeExpr [ 'step' Expr ] ')' Block
RangeExpr  ::= Expr '..' Expr | Expr '..=' Expr
Pattern    ::= Identifier | '(' Identifier (',' Identifier)* ')' 

Type System Rules
• RangeExpr must resolve to two values of matching type.
• Allowed types:
• int (default step = 1)
• float (requires step)
• If range is float and step is not provided → compile-time error

Codegen Considerations

For integer ranges:

start = a
end = b
inclusive = ..=
step = 1 (default)
direction = forward (unless `rev` or step < 0) 

For float ranges:

steps = ceil((end - start) / step)
loop: i = start + step * n 

Ensure float step multiplication uses n * step and clamps iteration to avoid floating point drift (optional precision safeguard).

Drawbacks
• Adds complexity to the language’s loop model.
• Requires runtime or compile-time handling of float drift.
• Potential confusion between rev loop and step -N unless clarified.
• Cannot fully prevent float precision issues in user logic.

Alternatives

Symbol-based (~, !)

Previously considered symbolic options like:

loop (i := 0 -> 10 ~2 !) { } 

These were rejected due to:
• Difficulty typing
• Lower readability
• Poor accessibility for new users

Reusing for (...)

We opted for loop to:
• Avoid confusion with for-each semantics in other languages
• Give Loom its own identity

Prior Art
• Rust: Uses for x in 0..10, rev, step_by, etc.
• Swift: Supports stride(from:to:by:)
• Python: Uses range(start, stop, step)
• Zig: Uses for (...) |i| with ranges

We draw heavily from Rust, but adapt to Loom’s more flexible and expressive syntax model.

Unresolved Questions
• Should rev be allowed for float ranges?
• Should rev imply step -1 for int ranges (if step omitted)?
• Should we allow custom iterator objects like range(0, 10, 2)?
• How to best avoid or warn about float drift?

Future Directions
• Support loop ((k, v) in map) with destructuring
• Support iterators (loop (x in someIterator))
• Add range filters or conditions (loop (i in 0..10 if i % 2 == 0))
• Allow loop labels and break/continue targeting

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