What's new in Node.js 27

21 points by loige a day ago on lobsters | 10 comments

bakkot | 21 hours ago

Two of these are mine! (Math.sumPrecise and Iterator.prototype.join.)

sumPrecise is fun; it turns out that maximally precise summation can be done reasonably efficiently. Originally the plan was to do a naive Math.sum and accept the error introduced by intermediate rounding but it's not that much slower to do it right so we might as well. I wanted to still call it Math.sum but engines pushed back because it's still somewhat slower, alas.

How did you get involved in TC39 stuff? I love reading through these proposals, and it's really interesting to see some of the discussions about quite specific details like the performance issues you mention here.

bakkot | 19 hours ago

Undergrad research was on static analysis of JS, which led to a job at a company (Shape Security) that was doing some interesting JS tooling with interesting constraints and was participating in the committee for that reason. ECMA is very much in the traditional "this is a way for companies to coordinate without running afoul of anti-trust" mold for standards bodies, so participation in the committee as such pretty much requires working for a member company.

That said, most conversation happens on GitHub (and sometimes Matrix) and is open to anyone. It's just participation at the actual meetings that requires being at a member company.

[OP] loige | 19 hours ago

Oh wow! That’s awesome! Thanks for these, especially join since I like all things iterators and iterator helpers! Are you still actively involved? Any other cool features coming next?

bakkot | 17 hours ago

Yes. Current big project is async versions of iterator helpers, which are going to support concurrency and thus are much more complicated. Other than that I am working on

altano | 16 hours ago

dedent is a great example of something I’ve hit countless times but never even thought to try and solve. Perfect stdlib material.

alanmeira | 3 hours ago

this is amazing, bakkot! I wish to see "uncoupling private fields from class syntax" part of JS. Really missed feature for my use.

conartist6 | 4 hours ago

Async iterator helpers are also a disaster.

Wrong in nearly every way at the same time..!

The async iterator protocol? It's fucking wrong. It's too slow to be useful for anything serious. It's too concrete to be a useful abstraction.

The design of iterator helpers, even the sync ones, is also atrocious. They go on the list of "Javascript, the bad parts". As the foremost expert on Javascript iterators, I could not in good faith suggest that anyone uses the built in interator helper APIs. There are just toi many footguns -- new footguns that did't exist. ...even scary security footguns that really really really really should not exist.

I call on the committee and the community to REJECT this proposal

jo3_l | 2 hours ago

I flagged your comment originally, but I'm leaving a comment instead in the hope that it will help you.

You're using incredibly incendiary language ("fucking wrong"? "atrocious"? "the bad parts"? "REJECT"?) while simultaneously providing no substantive content at all for other people who already aren't in the know to engage with. Clearly you hate the current design of the async iterator protocol... but that's about all I can glean from your comment. Sure, you allude vaguely to issues ("it's too slow", "it's too concrete", "there's too many footguns", "scary security footguns"), but there's no detail nor nuance to support an actual civil discussion! And that's notwithstanding the fact that the focus of the original discussion was not on the merits of iterators but bakkot's recent TC39 proposals more generally...

I'm forced to conclude that you simply keyword matched "iterator protocol" in an otherwise unrelated thread, and decided to come in guns ablaze to bash on someone else. To be clear, I'm sure you have real points to make and are quite knowledgeable, but your manner of engagement makes me steer well away from any thread you're involved in.

conartist6 | 15 minutes ago

I'm mad because I'm trying to blow the whistle on major structural problems and I can't get anyone engaged. But I agree that what I've said so far was provocative rather than productive, so here's the productive version:

There's two basic problems in play here. First is the design of async iteration. Second, the introduction of an "Iterator prototype" has introduced confusion (where none existed) as to whether an iterator is. Is it a duck-typed protocol? Or an instance of a particular class?

Let's talk about the design of async iteration. My complaint is that it injects synthetic deferrals. Every for loop that consumes an async iterator, at every step it consumes, must perform either a real deferral or a synthetic one. Synthetic deferrals are pure overhead in that they are work that produces no used result, and no other work can be done while that work is being done.

Fundamentally iteration is, well, I think Henry Ford invented it, he just called it "the assembly line". Its core proposition was the same as iterators: you have stations on a line, and the line runs continuously -- it might need never halt.

The tendency of an assembly line is to have many stations, each of which make a small change to each "widget" that passes through the station.

What mandatory async deferrals do, more or less, is create the position of "postman". The postman on the assembly line is the only person who is allowed to pick up a completed widget from one line worker and present it to another line worker. I hope this sounds patently absurd to you.

The problem is that there is only one postman. If you have ten stations it's station one processes the widget, then leaves it sitting. The postman comes, picks it up, walks it over to the internal mailroom, looks up the address of the next station, and then walks it back to station 2.

I call this time the postman spends walking around pure overhead because station 2 is right next to station 1 on the assembly line, and the result of all this business with the postman is the same result as if the the worker at station 1 just passed the widet they finished working on directly to station 2. This is of course exactly how a real assembly line works and what makes it so efficient.

So because we have this "there is only one postman" problem that rapidly becomes the bottleneck, basically the sane factory manager responds by having the workers process boxes full of widgets rather than individual widgets. This is basically why filesystem APIs are AsyncIterator<Buffer>. The Buffer is the crate you've inserted into the assembly line to avoid the does to the postman.

The problem with an iterator of buffers is that you've now wrecked the abstraction. Iterators are, as a pattern, a way to introduce some overhead in order to avoid revealing exactly how data is stored.

You would prefer that the instructions given to the person working each station are described in terms of transforming a single widget, not transforming a crate of widgets. Really the only thing the worker should need to know about the crate is how to take the items out of the "inbox" container one by one, and how to put them in "outbox" container one by one.

That is what i mean when I say that iterators are an abstraction over storage. If the line workers only ever see one widget at a time, then the factory is free to use any kind of crate or box or bag or pallete forklift... and the workers at the beginning and the end of the line won't need to know or care.

So the problem is that a slow postman forces us to process widgets one crate at a time, distorting the natural 1-by-1 flow of the line. To fix it, we let the work flow directly between workers.

It looks like this:

let streamIterator = {
  next() {
    if (valueAvailable)
      return { done: false, value }; 
    else
      return valueSource().then(value => ({done: false, value ))
  }
}

Now our code is sync when it can be, and async when it has to be, and now we can view files not as buffer iterators but character iterators again. You can try using it to access the filesystem if you wish: https://www.npmjs.com/package/@bablr/fs

There's a pretty famous blog post about all this too... https://blog.izs.me/2013/08/designing-apis-for-asynchrony/. It specifically advices against "synthetic" deferrals, and is why I am using that term for them.

altano | 16 hours ago

Comment removed by its author