Discuss a possible extension to designate also the starting bound as inclusive or exclusive, and discuss (a)symmetries and options.
4.7 KiB
Leo RFC 005: Countdown Loops
Authors
- Max Bruce
- Collin Chin
- Alessandro Coglio
- Eric McCarthy
- Jon Pavlik
- Damir Shamanaev
- Damon Sicore
- Howard Wu
Status
DRAFT
Summary
This proposal suggests adding countdown loops and inclusive loop ranges into the Leo language.
Motivation
In the current design of the language only incremental ranges are allowed. Though in some cases there's a need for loops going in the reverse direction. This example demonstrates the shaker sort algorithm where countdown loops are mocked:
function shaker_sort(a: [u32; 10], const rounds: u32) -> [u32; 10] {
for k in 0..rounds {
for i in 0..9 {
if a[i] > a[i + 1] {
let tmp = a[i];
a[i] = a[i + 1];
a[i + 1] = tmp;
}
}
for j in 0..9 { // j goes from 0 to 8
let i = 8 - j; // j is flipped
if a[i] > a[i + 1] {
let tmp = a[i];
a[i] = a[i + 1];
a[i + 1] = tmp;
}
}
}
return a;
}
Having a countdown loop in the example above could improve readability and usability of the language by making it more natural to the developer.
However, if we imagined this example using a countdown loop, we would see that it wouldn't be possible to count to 0; because the first bound of the range is inclusive and the second is exclusive, and loops ranges must use only unsigned integers.
// loop goes 0,1,2,3,4,5,6,7,8
for i in 0..9 { /* ... */ }
// loop goes 9,8,7,6,5,4,3,2,1
for i in 9..0 { /* ... */ }
Hence direct implementation of the coundown loop ranges would create asymmetry (1) and would not allow loops to count down to 0 (2). To implement coundown loops and solve these two problems we suggest adding an inclusive range bounds.
Design
Coundown loops
Countdown ranges do not need any changes to the existing syntax. However their functionality needs to be implemented in the compiler.
for i in 5..0 {}
Inclusive ranges
To solve loop asymmetry and to improve loop ranges in general we suggest adding inclusive range operator to Leo. Inclusive range would extend the second bound of the loop making it inclusive (instead of default - exclusive) therefore allowing countdown loops to reach 0 value.
// default loop: 0,1,2,3,4
for i in 0..5 {}
// inclusive range: 0,1,2,3,4,5
for i in 0..=5 {}
Example
The code example demostrated in the Motivation part of this document could be extended (or simplified) with the suggested syntax:
function shaker_sort(a: [u32; 10], const rounds: u32) -> [u32; 10] {
for k in 0..rounds {
for i in 0..9 { // i goes from 0 to 8
if a[i] > a[i + 1] {
let tmp = a[i];
a[i] = a[i + 1];
a[i + 1] = tmp;
}
}
for i in 8..=0 { // i goes from 8 to 0
if a[i] > a[i + 1] {
let tmp = a[i];
a[i] = a[i + 1];
a[i + 1] = tmp;
}
}
}
return a;
}
Possible Future Extension
While the ability to designate the ending bound of a loop as either exclusive or inclusive is critical as discussed below, we could also consider adding the ability to designate the starting bound of a loop as either exclusive or inclusive. If we do that, we run into a sort of asymmetry in the defaults for starting and ending bounds: the default for the starting bound is inclusive, while the default for ending bounds is exclusive.
The most symmetric but verbose approach is exemplified as follows:
0=..=5
for0 1 2 3 4 5
0<..=5
for1 2 3 4 5
0=..<5
for0 1 2 3 4
0<..<5
for1 2 3 4
5=..=0
for5 4 3 2 1 0
5>..=0
for4 3 2 1 0
5=..>0
for5 4 3 2 1
5>..>0
for4 3 2 1
That is, this approach makes exclusivensss an inclusiveness implicit. The use of<
vs.>
also indicates a loop direction, which can be inferred anyhow when theconst
bounds are resolved, so that would entail an additional consistency check, namely that the inequality sign/signs is/are consistent with the inferred loop direction.
Within the symmetric approach above, there are different options for defaults.
The most symmetric default would be perhaps =
for both bounds,
but that would be a different behavior from current Leo.
We could instead go for different defaults for starting and ending bounds,
i.e. =
for the starting bound and <
or >
(depending on direction) for the ending bound.
Drawbacks
No obvious drawback.
Effect on Ecosystem
Suggested change should have no effect on ecosystem because of its backward compatibility.
Alternatives
Coundown loops can be mocked manually.