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

LanguageSyntax
This proposalIterator.range(start, to, step?)
Bigint.range(start, to, step?)
Pythonrange(start, to, step?)
range(to)
JavaIntStream.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, ...)

LanguageSupport?
This proposalYes
PythonNo
JavaNo
Swift (Range)No
Swift (StrideTo)Yes
RustNo
HaskellYes
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>
LanguageReturn typeIterator 1๏ธโƒฃ / Iterable ๐Ÿ”ขLazy
This proposalInstantiation(Iterator)1๏ธโƒฃ Iteratorโœ…
PythonOwn๐Ÿ”ข Iterableโœ…
JavaInstantiation(Stream)โŒโœ…
Swift (Range)Own๐Ÿ”ข Iterableโœ…
Swift (StrideTo)Instantiation(StrideTo)๐Ÿ”ข IterableโŒ
RustOwn1๏ธโƒฃ Iteratorโœ…
HaskellInstantiation([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 implement Iterator<T> protocol but has a iterator() method that returns an Iterator. Must be used with for(int i: range.iterator())
  • Swift (StrideTo): According to the documentation of StrideTo, 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
Languagestarttostep
This proposalYesYesYes
PythonYesYesYes
JavaN/AN/AN/A
Swift (Range)YesYes๐Ÿ™ˆ?
Swift (StrideTo)N/AN/AN/A
RustNoNoN/A
HaskellN/AN/AN/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
LanguageAlgorithm
This proposalโœ–
Pythonโœ–
Javaโž•
Swift (StrideTo)โž•
Haskellโž•
F#โœ–

Inclusive or exclusive?

Language[start,to)(start,to)(start,to][start,to]
This proposalYesNoNoYes
PythonYesNoNoNo
JavaYes
(range())
NoNoYes
(rangeClosed())
SwiftYes
(1..<3)
NoNoYes
(1...3)
RustYes
((1..3))
NoNoYes
((1..=3))
HaskellNoNoNoYes
F#NoNoNoYes

(Too big) Overflow behavior for Int type (BigInt-like range not included)

LanguageBehavior
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)
}
x = 9223372036854775806 :: Int
[x..] !! 2

(Too small) Floating point error behavior

  • N/A: Doesn't support non-integer step
LanguageBehavior
This proposalNot decided yet
PythonN/A
JavaN/A
Swift (Range)N/A
Swift (StrideTo)Emit nothing
RustN/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

LanguageSyntax
This proposalNot yet
Pythonx in range
JavaMaybe range.anyMatch(testFn)?
Swiftrange.contains(x)
Rustrange.contains(&item)
Haskellelem x [y..z]
F#Seq.contains x seq {start..to}

[[Get]] (range[index])

LanguageSyntax
This proposalNo
Pythonr[x]
JavaNo
Swift (Range)r.subscript(x)
Swift (StrideTo)No
RustNo
Haskell[x..y] !! i
F#No?

[Symbol.slice] (slice notation proposal)

LanguageSyntaxWith step
This proposalNot yetNot yet
Pythonrange[i:j]range[i:j:step]
JavaNoNo
Swift (Range)range.clamped(to)No
Swift (StrideTo)NoNo
Rustrange[start .. to]No
HaskellNo?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.operation for that.
  • In ECMAScript, composing with existing language features is enough (e.g. Python min() with ES Math.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 of x in range
  • max(): In ES we do Math.max(...range)
  • min(): In ES we do Math.min(...range)
  • len(): In ES we do [...range].length
  • r.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 feedback
  • randomElement(): Not included yet, wait for community feedback
  • overlaps: Not included yet, wait for community feedback
  • description: Intl.NumberFormat?

Many methods can be handled by the Iterator helper proposal. Many methods require a non-lazy semantics.

Rust

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 for IEnumerable<T>(similar to Iteratable<T> in TS).

Notes

  1. Python means Python 3 in this document.

References