Comparison
April 6, 2023 ยท View on GitHub
Work in progress
Based on the documentation and REPL of other languages, might have error in it.
Semantics
Syntax
| Language | Syntax |
|---|---|
| This proposal | Iterator.range(start, to, step?) Bigint.range(start, to, step?) |
| Python | range(start, to, step?) range(to) |
| Java | IntStream.range(start, to) LongStream.range(start, to) |
Swift (Range) | start...to start..<to |
Swift (StrideTo) | stride(from: var_start, to: var_to, by: var_step) |
| Rust | (start..to) (start..=to) |
| Haskell | [start,next_element_to_infer_step..to] |
| F# | seq { start .. step .. to } |
Haskell: The [start..to] syntax produces a list. Due to lazy evaluation in Haskell, its range semantics are different from most languages.
Support decimal steps (0.1, 0.2, 0.3, ...)
| Language | Support? |
|---|---|
| This proposal | Yes |
| Python | No |
| Java | No |
Swift (Range) | No |
Swift (StrideTo) | Yes |
| Rust | No |
| Haskell | Yes |
| F# | Yes |
Return type
Define:
- Iterator: Similar to ES iterator protocol
- Iterable: Similar to ES objects with
[Symbol.iterator](e.g. has a__iter__()method) - Non-Lazy: The range generates values in a non-lazy way
- Own: The range has its own class / struct / ...
- Instantiation: The range doesn't have its own class, instead, it is implementing a more generic type like
StrideTo<int>
| Language | Return type | Iterator 1๏ธโฃ / Iterable ๐ข | Lazy |
|---|---|---|---|
| This proposal | Instantiation(Iterator) | 1๏ธโฃ Iterator | โ |
| Python | Own | ๐ข Iterable | โ |
| Java | Instantiation(Stream) | โ | โ |
Swift (Range) | Own | ๐ข Iterable | โ |
Swift (StrideTo) | Instantiation(StrideTo) | ๐ข Iterable | โ |
| Rust | Own | 1๏ธโฃ Iterator | โ |
| Haskell | Instantiation([Num]) | N/A | โ |
| F# | Instantiation(seq<'T>) | ๐ข Iterable | โ |
- This proposal: It doesn't have its own class currently but it has its own prototype
%RangeIteratorPrototype%and has unique getters on it. - Java: The base interface of
IntStream(Stream) doesn't implementIterator<T>protocol but has aiterator()method that returns an Iterator. Must be used withfor(int i: range.iterator()) - Swift (
StrideTo): According to the documentation ofStrideTo, laziness is opt-in. - Rust: See https://github.com/tc39/proposal-Number.range/issues/17#issuecomment-642064127
- Haskell: No Iterator / Iterable. The laziness is in the language.
The idea of a side-effecting iterator is antithetical to the Haskell Way.(start StackOverflow)
Immutable (start, to and step cannot be changed)
- Yes: immutable
- No: Mutable
- ๐ means this value is not exposed to developers
| Language | start | to | step |
|---|---|---|---|
| This proposal | Yes | Yes | Yes |
| Python | Yes | Yes | Yes |
| Java | N/A | N/A | N/A |
Swift (Range) | Yes | Yes | ๐? |
Swift (StrideTo) | N/A | N/A | N/A |
| Rust | No | No | N/A |
| Haskell | N/A | N/A | N/A |
| F# | ? | ? | ? |
Algorithm (for floating point number)
Generally tested with range 0 to 1 with step 0.1
- โ:
thisValue = last + step - โ:
thisValue = start + step * i - ?: Unknown
| Language | Algorithm |
|---|---|
| This proposal | โ |
| Python | โ |
| Java | โ |
Swift (StrideTo) | โ |
| Haskell | โ |
| F# | โ |
Inclusive or exclusive?
| Language | [start,to) | (start,to) | (start,to] | [start,to] |
|---|---|---|---|---|
| This proposal | Yes | No | No | Yes |
| Python | Yes | No | No | No |
| Java | Yes ( range()) | No | No | Yes ( rangeClosed()) |
| Swift | Yes ( 1..<3) | No | No | Yes ( 1...3) |
| Rust | Yes ( (1..3)) | No | No | Yes ( (1..=3)) |
| Haskell | No | No | No | Yes |
| F# | No | No | No | Yes |
(Too big) Overflow behavior for Int type (BigInt-like range not included)
| Language | Behavior |
|---|---|
| This proposal | โ Not decided yet |
| Python | โ Allowed, but fails len() etc. with OverflowError |
| Java | โซ Emit nothing |
Swift (Range) | N/A, can't set to bigger than 9223372036854775807 |
Swift (StrideTo) | โซ Emit nothing |
| Rust | โพ Endless loop (Production) / โ Panic (Debug) |
| Haskell | โ Exception |
| F# | ? |
- Java: Test with code
IntStream
.rangeClosed(Integer.MAX_VALUE, Integer.MAX_VALUE+100)
.forEach(s -> System.out.print(s + " "));
- Swift: Test with code
for i in stride(from: 1.7E+308, to: (1.7E+308)+3, by: 1) {
print(i)
}
- Rust: From the Rust documentation:
if you use an integer range and the integer overflows, it might panic in debug mode or create an endless loop in release mode.(https://doc.rust-lang.org/std/ops/struct.RangeFrom.html) - Haskell: Test with code
x = 9223372036854775806 :: Int
[x..] !! 2
(Too small) Floating point error behavior
- N/A: Doesn't support non-integer step
| Language | Behavior |
|---|---|
| This proposal | Not decided yet |
| Python | N/A |
| Java | N/A |
Swift (Range) | N/A |
Swift (StrideTo) | Emit nothing |
| Rust | N/A |
| haskell | ? |
| F# | ? |
- Swift: Test with code
for i in stride(from: 1e323, to: (1e323 + 1e-323 * 2), by: 1e-323) { print(i) } - Haskell: Test with code
[1.7976931348623157e308..1.7976931348623158e308] !! 1500 == [1.7976931348623157e308..1.7976931348623158e308] !! 15
Protocols/methods that range implements
Will try to use ECMAScript equivalent names
range.includes(x)
Semantics: Is given x in the range
e.g. range(0, 1).includes(0.5) should be false
| Language | Syntax |
|---|---|
| This proposal | Not yet |
| Python | x in range |
| Java | Maybe range.anyMatch(testFn)? |
| Swift | range.contains(x) |
| Rust | range.contains(&item) |
| Haskell | elem x [y..z] |
| F# | Seq.contains x seq {start..to} |
[[Get]] (range[index])
| Language | Syntax |
|---|---|
| This proposal | No |
| Python | r[x] |
| Java | No |
Swift (Range) | r.subscript(x) |
Swift (StrideTo) | No |
| Rust | No |
| Haskell | [x..y] !! i |
| F# | No? |
[Symbol.slice] (slice notation proposal)
| Language | Syntax | With step |
|---|---|---|
| This proposal | Not yet | Not yet |
| Python | range[i:j] | range[i:j:step] |
| Java | No | No |
Swift (Range) | range.clamped(to) | No |
Swift (StrideTo) | No | No |
| Rust | range[start .. to] | No |
| Haskell | No? | No? |
| F# | No? | No? |
Omitted protocols / methods:
Here are the common features in other languages omitted in the previous comparison because
- It represents an abstract operation on any sequence-like object but in ECMAScript we don't have a
Symbol.operationfor that. - In ECMAScript, composing with existing language features is enough (e.g. Python
min()with ESMath.min(...range)) - It makes no sense for a range object
- It is covered by the Iterator helper proposal
Python
Ranges implement all of the common sequence operations except concatenation and repetition (due to the fact that range objects can only represent sequences that follow a strict pattern and repetition and concatenation will usually violate that pattern).
x not in range: Looks like a simple inversion ofx in rangemax(): In ES we doMath.max(...range)min(): In ES we doMath.min(...range)len(): In ES we do[...range].lengthr.index(x): In ES we do[...range].indexOf(x)r.count(x): Lack of[Symbol.count]in ES.r1 == r2: Lack of[Symbol.equal]in ES.
Java
IntStream and LongStream. Most of methods listed in the documentation likely can be handled by the Iterator helper proposal.
Swift
isEmpty: Not included yet, wait for community feedbackrandomElement(): Not included yet, wait for community feedbackoverlaps: Not included yet, wait for community feedbackdescription: Intl.NumberFormat?
Many methods can be handled by the Iterator helper proposal. Many methods require a non-lazy semantics.
Rust
isEmpty: Not included yet, wait for community feedbackimpl Index<Range<usize>> for String: Related to the slice notation proposal, also see https://github.com/tc39/proposal-Number.range/issues/22#issuecomment-641864077
Haskell
- Most of functions are common operations to lists therefore not included.
F
- Sequences are represented by the
seq<'T>type, which is an alias forIEnumerable<T>(similar toIteratable<T>in TS).
Notes
- Python means Python 3 in this document.
References
- Python: https://docs.python.org/3/library/stdtypes.html?#range
- Java: https://docs.oracle.com/javase/8/docs/api/java/util/stream/IntStream.html#range-int-int-
- Swift
Range: https://developer.apple.com/documentation/swift/Range - Swift
StrideTo: https://developer.apple.com/documentation/swift/strideto - Rust
Range{From,To,Inclusive,ToInclusive}: https://doc.rust-lang.org/std/ops/struct.Range.html - Haskell: https://hackage.haskell.org/package/base-4.14.0.0/docs/Data-List.html
- F#: https://docs.microsoft.com/en-US/dotnet/fsharp/language-reference/sequences and https://msdn.microsoft.com/visualfsharpdocs/conceptual/collections.seq-module-%5bfsharp%5d