# Static iterator helpers, e.g. Iterator.map

**URL:** <https://es.discourse.group/t/static-iterator-helpers-e-g-iterator-map/2659>\
**Category:** 💡 Ideas\
**Created:** [October 15, 2026, 10:48pm UTC](https://es.discourse.group/t/static-iterator-helpers-e-g-iterator-map/2659 "2026-10-15T22:48:06Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![conartist6](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/conartist6/32/515_2.png) [@conartist6](https://es.discourse.group/u/conartist6)\
**Post date:** [October 15, 2026, 10:48pm UTC](https://es.discourse.group/t/static-iterator-helpers-e-g-iterator-map/2659/1 "2026-10-15T22:48:06Z")

</div>

The idea is to introduce static aliases for all the iterator helpers that have so far been introduced through the prototype chain.

The most visible new function would be `Iterator.map(fn, iter)` as a mirror of `Iterator.prototype.map(fn)`.

This is generally useful for defensive coding practices. Normal iterator helpers presume that you trust the provider of the iterator protocol. If you don't (or don't necessarily) trust the provider, static helpers would be safe to use when instance helpers would not be.

---

<div class="post-metadata">

**Author:** ![ljharb](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/ljharb/32/8_2.png) [@ljharb](https://es.discourse.group/u/ljharb)\
**Post date:** [October 15, 2026, 11:02pm UTC](https://es.discourse.group/t/static-iterator-helpers-e-g-iterator-map/2659/2 "2026-10-15T23:02:52Z")

</div>

That's what `Iterator.from()` is for - you throw anything iteratorlike into it, and it'll give you a best-effort conforming Iterator, with all the prototype methods you'd expect.

---

<div class="post-metadata">

**Author:** ![conartist6](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/conartist6/32/515_2.png) [@conartist6](https://es.discourse.group/u/conartist6)\
**Post date:** [October 15, 2026, 11:07pm UTC](https://es.discourse.group/t/static-iterator-helpers-e-g-iterator-map/2659/3 "2026-10-15T23:07:47Z")

</div>

Yeah I get that it's for that, but it's still just a little harder to write `Iterator.from(iter).map(fn)` than it is to write `Iterator.map(fn, iter)`. Because you know it could be that easy, it feels like the language designers giving you a gentle push back against doing this.

That is my concern: the language is offering users pushback as if they're doing something wrong, but actually that is the best pattern when working in a defensive coding style. We all benefit from defensive coding (that is to say, even as users), so we should make it as easy as possible to do the most durable thing.

---

<div class="post-metadata">

**Author:** ![conartist6](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/conartist6/32/515_2.png) [@conartist6](https://es.discourse.group/u/conartist6)\
**Post date:** [October 15, 2026, 11:11pm UTC](https://es.discourse.group/t/static-iterator-helpers-e-g-iterator-map/2659/4 "2026-10-15T23:11:04Z")

</div>

I'm particularly concerned because I don't want it to be significantly easier to write `iter.map(fn)`. I don't want to see people do something insecure because it's just slightly more convenient, but my experience with people suggests that that is exactly the kind of thing they are likely to do

---

<div class="post-metadata">

**Author:** ![ljharb](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/ljharb/32/8_2.png) [@ljharb](https://es.discourse.group/u/ljharb)\
**Post date:** [October 15, 2026, 11:18pm UTC](https://es.discourse.group/t/static-iterator-helpers-e-g-iterator-map/2659/5 "2026-10-15T23:18:34Z")

</div>

It's much easier to write it with more than one helper, though, and I suspect most use cases involve combining the helpers.

---

<div class="post-metadata">

**Author:** ![conartist6](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/conartist6/32/515_2.png) [@conartist6](https://es.discourse.group/u/conartist6)\
**Post date:** [October 15, 2026, 11:21pm UTC](https://es.discourse.group/t/static-iterator-helpers-e-g-iterator-map/2659/6 "2026-10-15T23:21:50Z")

</div>

Right now you're kind of stuck in a half-there state. You might write something like:

```js
let result = Iterator.from(iter)
   .map(mapFn)
   .filter(filterFn)

```

This is technically enough in terms of defensive style, but it's still split between two idioms: part of it is based on static methods, part on instance methods.

The committee has indicated through its designation of the state of the pipeline proposal that some method of pipelining is desired to be supported. Thus it makes complete sense to me given the direction the language is going to offer iterator helpers that are used through a pipelining operator. These would be the static methods. E.g.

```js
let { filter, map } = Iterator;

let result |>
  filter(filterFn, %)
  map(mapFn, %)

```

---

<div class="post-metadata">

**Author:** ![senocular](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/senocular/32/642_2.png) [@senocular](https://es.discourse.group/u/senocular)\
**Post date:** [October 15, 2026, 11:41pm UTC](https://es.discourse.group/t/static-iterator-helpers-e-g-iterator-map/2659/7 "2026-10-15T23:41:36Z")

</div>

I'm not sure `Iterator.from()` is much help if you don't trust the provider? It only wraps the argument if doesn't already inherit from Iterator. If it does, there's nothing stopping it from providing helper overrides of its own if that's the concern.

```javascript
Iterator.from(new class extends Iterator {
  map() {
    console.log("custom map")
  }
}).map(x => x) // "custom map"

```

---

<div class="post-metadata">

**Author:** ![ljharb](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/ljharb/32/8_2.png) [@ljharb](https://es.discourse.group/u/ljharb)\
**Post date:** [October 16, 2026, 12:10am UTC](https://es.discourse.group/t/static-iterator-helpers-e-g-iterator-map/2659/8 "2026-10-16T00:10:19Z")

</div>

True, but that's because it extends Iterator - I'm talking about things that are non-Iterator iterators (note `I` vs `i`)

---

<div class="post-metadata">

**Author:** ![aclaymore](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/aclaymore/32/501_2.png) [@aclaymore](https://es.discourse.group/u/aclaymore)\
**Post date:** [October 16, 2026, 12:28am UTC](https://es.discourse.group/t/static-iterator-helpers-e-g-iterator-map/2659/9 "2026-10-16T00:28:49Z")

</div>

Static functions was presented:

> <https://github.com/tc39/notes/blob/53a59ad71704e669d488a6b67baf940bfe2fe134/meetings/2022-09/sep-14.md>

---

<div class="post-metadata">

**Author:** ![conartist6](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/conartist6/32/515_2.png) [@conartist6](https://es.discourse.group/u/conartist6)\
**Post date:** [October 16, 2026, 11:33am UTC](https://es.discourse.group/t/static-iterator-helpers-e-g-iterator-map/2659/10 "2026-10-16T11:33:02Z")

</div>

> It only wraps the argument if doesn't already inherit from Iterator

O\_O

How. Did. It. Get. This. Wrong.

That's wrong. There's no mincing words, it's simply wrong.

It means that you CAN'T EVER BE SURE THAT YOU ARE REALLY CALLING _ANY_ OF THESE METHODS. There is no concise defensive style that also supports chaining.

I'm not smoking crazy pills am I? The ONLY way to not risk getting hurt would be to invoke the iterator helpers as if they actually were already static:

```js
let { map } = Iterator.prototype;

// still feels like the language does not want you to do this
// Don't forget to invoke `[Symbol.iterator]()` first if needed
map.call(iter, x => x);

```

Why? Why on earth would none of this have ever been considered? At all? I went through the meeting minutes you linked @aclaymore but found no discussion about this.

---

<div class="post-metadata">

**Author:** ![aclaymore](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/aclaymore/32/501_2.png) [@aclaymore](https://es.discourse.group/u/aclaymore)\
**Post date:** [October 16, 2026, 12:02pm UTC](https://es.discourse.group/t/static-iterator-helpers-e-g-iterator-map/2659/11 "2026-10-16T12:02:02Z")

</div>

> [@conartist6](#):
>
> I went through the meeting minutes you linked @aclaymore but found no discussion about this.

It's the very first topic in the minutes for that day

---

<div class="post-metadata">

**Author:** ![aclaymore](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/aclaymore/32/501_2.png) [@aclaymore](https://es.discourse.group/u/aclaymore)\
**Post date:** [October 16, 2026, 12:04pm UTC](https://es.discourse.group/t/static-iterator-helpers-e-g-iterator-map/2659/12 "2026-10-16T12:04:00Z")

</div>

If you don't trust the iterator, why would wrapping it and calling the real '.map' method be any safer, it's still doing to trigger the code in the iterator to run.

---

<div class="post-metadata">

**Author:** ![senocular](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/senocular/32/642_2.png) [@senocular](https://es.discourse.group/u/senocular)\
**Post date:** [October 16, 2026, 12:10pm UTC](https://es.discourse.group/t/static-iterator-helpers-e-g-iterator-map/2659/13 "2026-10-16T12:10:25Z")

</div>

You could also create your own wrapper. The original would only be providing values, not the interface; that's coming from the wrapper generator.

```javascript
function* IterFrom(obj) {
  yield* obj
}

IterFrom(new class extends Iterator {
  map() {
    console.log("custom map")
  }
}).map === Iterator.prototype.map // true

```

I also vaguely remember there being some discussion on github about whether or not these methods should be in the prototype or not... that's probably from [Consider making the library for Iterables rather than Iterators · Issue #8 · tc39/proposal-iterator-helpers · GitHub](https://github.com/tc39/proposal-iterator-helpers/issues/8)

---

<div class="post-metadata">

**Author:** ![conartist6](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/conartist6/32/515_2.png) [@conartist6](https://es.discourse.group/u/conartist6)\
**Post date:** [October 16, 2026, 12:18pm UTC](https://es.discourse.group/t/static-iterator-helpers-e-g-iterator-map/2659/14 "2026-10-16T12:18:26Z")

</div>

Just to satisfy myself that you are correct that such an egregious flaw has been introduced, I went and experimentally confirmed it:

```javascript
class MalignIterator extends Iterator {
  value = 1;
  *map() { return; }
  next() {
    
    return {
      done: this.value > 3,
      value: this.value++
   };
  }
  [Symbol.iterator]() { return this }
}

// If we could trust `map`, the result would be 1, 2, 3
[...Iterator.from(new MalignIterator()).map(x => x)]; // []

```

You see why it matters now that the `map` implementation can be trusted even though the iterator executes arbitrary code: A trusted implementation of `map` makes guarantees that the engineer may rely on, such as that `map` will output the same number of values that it consumes as input.

---

<div class="post-metadata">

**Author:** ![conartist6](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/conartist6/32/515_2.png) [@conartist6](https://es.discourse.group/u/conartist6)\
**Post date:** [October 16, 2026, 12:37pm UTC](https://es.discourse.group/t/static-iterator-helpers-e-g-iterator-map/2659/15 "2026-10-16T12:37:56Z")

</div>

You could create your own wrapper. Of course you don't need _any_ wrapper if you just use static helper methods!

But again if you have to hand-write your own variant of `Iterator.from` that feels bad. It feels like the language designers are pushing back and saying "no, we never intended any of this". Either you copy paste your wrapper every time you need to use it or you make some library like [iter-tools](https://github.com/iter-tools/iter-tools/) (which I maintain) and use it everywhere.

I reiterate: the language should not make it hard to do the right thing. The right thing should also be the easiest to do. Make it easy to do the right thing and coders will, in statistical aggregate, do the right thing. Make it easy to do the wrong thing and coders will, in aggregate, do the wrong thing.

Anyway if the message from the committee is really that everyone should abandon the builtin functionality and use my library, I'm here for it. They'd be writing code that is more safe and more correct than native code.

---

<div class="post-metadata">

**Author:** ![conartist6](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/conartist6/32/515_2.png) [@conartist6](https://es.discourse.group/u/conartist6)\
**Post date:** [October 16, 2026, 12:48pm UTC](https://es.discourse.group/t/static-iterator-helpers-e-g-iterator-map/2659/16 "2026-10-16T12:48:35Z")

</div>

> [@conartist6](#):
>
> `Iterator.from(iter).map()`

I think the single biggest complaint I have is that this 100% totally absolutely definitely very very much looks like it's code to invoke `Iterator.map` (and making matters worse, it almost always is (maybe even always, outside of attacks)).

It is then the principle of least surprise that dictates that the code should always do what it looks like it does (and usually does).

---

<div class="post-metadata">

**Author:** ![conartist6](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/conartist6/32/515_2.png) [@conartist6](https://es.discourse.group/u/conartist6)\
**Post date:** [October 16, 2026, 12:57pm UTC](https://es.discourse.group/t/static-iterator-helpers-e-g-iterator-map/2659/17 "2026-10-16T12:57:47Z")

</div>

As horrible as it is, this is one time when I would advocate a breaking change. These have happened several times in the history of the web, and I'm willing to bet all my marbles that nobody in the world is relying on this behavior yet so that nothing would break in practice.

We should be able to more-or-less verify that (I presume) by making an experimental browser with the change, then seeing if the top few million websites work normally. I'm under the impression that a process like this has been used in the past to quantify the impact of technically-breaking changes, like the past changes involving SGML vs HTML comment parsing rules.

---

<div class="post-metadata">

**Author:** ![conartist6](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/conartist6/32/515_2.png) [@conartist6](https://es.discourse.group/u/conartist6)\
**Post date:** [October 16, 2026, 1:17pm UTC](https://es.discourse.group/t/static-iterator-helpers-e-g-iterator-map/2659/18 "2026-10-16T13:17:10Z")

</div>

Whatever the loudest whistle is that can be blown, I am blowing it. I am pulling the cord to stop the assembly line. I am triggering a retrospective.

We fucked up.

Really bad.

---

<div class="post-metadata">

**Author:** ![bakkot](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/bakkot/32/22_2.png) [@bakkot](https://es.discourse.group/u/bakkot)\
**Post date:** [October 16, 2026, 6:42pm UTC](https://es.discourse.group/t/static-iterator-helpers-e-g-iterator-map/2659/19 "2026-10-16T18:42:11Z")

</div>

This thread is very silly. No, this was not a mistake. This is the correct behavior. It is on subclasses of `Iterator` to implement compatible behavior for `.map`; that's what it _means_ to be a subclass. If you want to be defensive against a subclass failing to implement compatible behavior, you need to do `Iterator.prototype.map.call`, just like if you want to take a `Map` and be defensive against it having incompatible behavior for its methods you'd need to do `Map.prototype.get.call` or whatever. `Iterator.from` is only a convenience method for getting an `Iterator` instance out of things which are _not_ already instances, not a tool for being defensive against ill-behaved subclasses.

The "right thing" for almost all code is to have a contract for your public functions and require callers to obey it, not to add a bunch of overhead everywhere just in case a caller is going out of their way to violate it. The language is not and will not be designed on the assumption that normal uses require being defensive against ill-behaved subclasses and similar.

---

<div class="post-metadata">

**Author:** ![tabatkins](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/tabatkins/32/170_2.png) [@tabatkins](https://es.discourse.group/u/tabatkins)\
**Post date:** [October 16, 2026, 7:38pm UTC](https://es.discourse.group/t/static-iterator-helpers-e-g-iterator-map/2659/20 "2026-10-16T19:38:35Z")

</div>

Strong agree with Bakkot here. Subclasses can _always_ override a method in a fucked up way, but that's an extremely intentional part of class-based design. Don't violate the method's contract, and don't use libraries that violate the method's contract. If you really do super care about getting the superclass's exact behavior, we already have mechanism to do that, but it's very rarely what you need to do.

There's no need to "protect" people here; a badly-written library can violate the contract, sure, but it can also do _arbitrary additional things_. It's arbitrary code! Don't run arbitrary code that you don't trust! If you've loaded a hostile library and think that a static helper will protect you, the hostile library can override that too!

[Next page](https://es.discourse.group/t/static-iterator-helpers-e-g-iterator-map/2659.md?page=2)
