1 of 17

Iterator Chunking

for Stage 2.7

Michael Ficarra • TC39 • May 2025

2 of 17

reminder: problem

consume an iterator as either overlapping or�non-overlapping subsequences of configurable size

3 of 17

solution: consuming non-overlapping subsequences

arrays of length 3:

0

1

2

3

4

5

6

7

8

an iterator of digits:

0

1

2

3

4

5

6

7

8

0

1

2

3

4

5

6

7

8

0

1

2

3

4

5

6

7

8

Iterator.prototype.chunks( chunkSize )

4 of 17

solution: consuming overlapping subsequences

0

1

2

3

4

5

6

7

an iterator of digits:

0

1

2

3

4

5

6

7

arrays of length 4:

0

1

2

3

4

5

6

7

0

1

2

3

4

5

6

7

0

1

2

3

4

5

6

7

0

1

2

3

4

5

6

7

Iterator.prototype.windows( windowSize )

5 of 17

last minute change

6 of 17

remaining open design question

7 of 17

8 of 17

problem: window size > number of yielded values

0

1

2

an iterator of digits:

0

1

2

?

.windows(4):

9 of 17

options:

  1. yield no windows (spec text today)
  2. throw when .next() is called (PR #14)
  3. yield a single undersized window (PR #15)
  4. yield a window that has been padded with undefined or similar (PR #16)
  5. an additional argument or additional method to allow the developer to choose between some or all of the above

10 of 17

context: .chunks() may yield undersized final chunk

arrays of length 3:

0

1

2

3

4

5

6

7

8

9

an iterator of digits:

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

(+1)

11 of 17

context: behaviour in other languages

language

library / type

function

behaviour

C++

std::ranges::views

slide

empty (1)

Clojure

core

partition

empty (1)

Elm

List.extra

groupsOfWithStep

empty (1)

Elm

List.extra

greedyGroupsOfWithStep

undersized (3)

Haskell

split

divvy

empty (1)

Java

Stream

Gatherers.windowSliding

undersized (3)

Kotlin

Iterable

windowed

parameterised ( 1* or 3 )

Python

more-itertools

windowed

padded (4)

Ruby

Enumerable

each_cons

empty (1)

Rust

Iterator

map_windows

empty (1)

Rust

slice

windows

empty (1)

Scala

Seq

sliding

undersized (3)

* default

12 of 17

context: behaviour in JS libraries

library

type

function

behaviour

extra-iterable

Iterable

chunk

undersized (3)

iter-tools

Iterable

window

empty (1)

iter-tools

Iterable

windowAhead

padded (4)

itertools-ts

Iterator / Iterable

chunkwiseOverlap

parameterised ( 3* or 1 )

Ramda

List

aperture

empty (1)

* default

13 of 17

champion's preferences

empty (1) seems best and is most common

undersized (3) is also acceptable and aligns with .chunks()

throw (2) is unprecedented and an abuse of exceptions

padded (4) without passing the pad value is very bad

a parameter is fine and flexible, but should there be a default?

separate methods would also be fine

14 of 17

use-case driven

  • running/continuous computations, such as averages

empty (1) or throw (2) or undersized (3)

  • context-sensitive algorithms, such as pairwise comparisons

empty (1) or throw (2)

  • carousels and their analogues

throw (2) or undersized (3)

15 of 17

should we reconsider

.chunks() behaviour?

16 of 17

assigned Stage 2.7 reviewers

ACE (Ashley Claymore)

JHD (Jordan Harband)

JMN (Jesse Alama)

17 of 17

Stage 2.7?

(assuming a simple solution to the open design question)