Number.range & BigInt.range
March 2020
Jack Works
https://github.com/Jack-Works/proposal-Number.range
(Polyfill & Spec text available in the repo)
In other languages...
for x in 0..10 { // Rust
println!("{}", x);
}
for n in range(6): # Python
print(n)
foreach(var item in 1..100) // C#
{
Console.WriteLine(item);}
for (i in 1..4) print(i) // Kotlin
@for $i from 1 through $grid-columns { // SCSS
.grid-#{$i} {
@include grid-base($i);
@extend .grid-block;
}
}
: bat
FOR /L %%G IN (1,1,5) DO echo %%G
Today in JS
At least 20 different implementations in a single stackoverflow question
Tons of libraries providing a range: math.js, lodash, underscore.js, ramda, d3, range, fill-range, multi-integer-range, ……
;[...Array(5).keys()] // ES6
function range(size, startAt = 0) {
return [...Array(size).keys()].map(i => i + startAt)
}
_.range(1, 11) // lodash
Array.apply(null, Array(5)).map(function(_, i) {
return i // ES5 compatible
})
Array.from({ length: 20 }, (x, i) => i)
Array.from(new Array(20), (x, i) => i + lowerBound)
Array(10)
.fill(1)
.map((x, y) => x + y)
const range = (start, stop, step = 1) =>
Array(Math.ceil((stop - start) / step))
.fill(start)
.map((x, y) => x + y * step)
const RANGE = (a, b) =>
Array.from(
(function*(x, y) {
while (x <= y) yield x++
})(a, b)
)
Motivation
Without these functions, the language feels incomplete, and is a paper cut to what could be a very polished experience. Bringing this into the platform will improve performance of the web, and developer productivity as they no longer have to implement these common functions.
—— String.prototype.{padStart,padEnd}
Usage
for (const i of BigInt.range(0n, 43n)) console.log(i) // 0n to 42n
// With iterator helper proposal
Number.range(0, Infinity).take(1000).filter(x => !(x % 3)).toArray()
function* even() {
for (const i of Number.range(0, Infinity)) if (i % 2 === 0) yield i
}
[...Number.range(1, 100, 2)] // odd number from 1 to 99
Proposed API
interface NumberConstructor {
// Number.range(from, to, step?)
range(from: number, to: number, step?: number): Iterator<number>
}
interface BigIntConstructor {
// BigInt.range(from, to, step?)
range(from: bigint, to: bigint, step?: bigint): Iterator<bigint>
}
Goals
Non-goals
Wait for discussions (available at GitHub repo)
// What to do if the direction doesn't match? (GH #5)
// a. throw an Error | b. ignore the direction, infer from `from` and `to
// c. do nothing, cause a dead loop | d. yield nothing
Number.range(0, 10, -5)
Number.range(42, 100, 1e-323) // How to deal with this? This will cause a dead loop (GH #7)
BigInt.range(0, Infinity) // Infinite sequence for BigInt (GH #8)
oneToTen.includes(42) // Add some helper methods (GH#12)
Number.range(10) // Means [0, 10) (GH#18), [10, Infinity) (GH#14) or TypeError?
// Let it return an object with @@iterator instead of a raw iterator (GH#17)
Stage 1?