HNHacker News
TopNewBestAskShowJobs

bakkoting

358 karma · joined March 8, 2016

TC39.
submissionscomments
bakkoting··on Breaking Up with Long Tasks or: how I learned to group loops and wield the yield
There's some progress on that proposal, just happening elsewhere. https://github.com/tc39/proposal-esm-phase-imports defines machinery for importing a ModuleSource object which you can instantiate as a Worker, and once that's done module expressions would just be syntax which evaluates to a ModuleSource rather than needing a separate import.
bakkoting··on My son (9 yrs old) used plain JavaScript to make a game, and wants your feedback
I've been writing JavaScript since I was about your son's age and am now one of the editors of the JavaScript specification. His code is much much better than mine was at his age!

I have one piece of feedback for him about the code itself, in case he's interested (of course the important part is the game, not the code, but I'm more qualified to give feedback on the JS): put `"use strict"` at the top of every <script>.

bakkoting··on Wasmer 5.0
> I would guess worst case QuickJS probably can compile to WASM

That's actually exactly what Figma is doing for their plugins. [1] Seems to be working ok, though not without some pain [2].

[1] https://www.figma.com/blog/an-update-on-plugin-security/

[2] https://macwright.com/2024/03/29/figma-plugins

bakkoting··on Australia/Lord_Howe is the weirdest timezone
Here's a good essay about that: So You Want To Abolish Time Zones [1]

[1] https://qntm.org/abolish

bakkoting··on Proposal: JavaScript Structs
> instead of exclusively focusing on making them easier to use or more performant, they are constantly adding features

I appreciate that this is mostly just a generic rant, but it's not really suitable here, because this is a feature which is being added with the sole goal of improved performance.

There's only so much you can to optimize the extremely dynamic regular objects in JS, and there's no hope of using them for shared-memory multithreading. The purpose of this proposal is to have a less dynamic kind of object which can be made more performant and which can be made suitable for shared-memory multithreading.

bakkoting··on Magic Wormhole: get things from one computer to another, safely
If you already have node and npm installed, and are happy running random binaries from the internet, you can `npx magic-wormhole` to run this without any further setup. It just wraps wormhole-william, which is the go implementation of magic-wormhole.

I put it on npm primarily so I could send things to other JS developers an absolute minimum of fuss: one command, total, instead of installing a tool and then running the command.

bakkoting··on Jiff: Datetime library for Rust
"Proposed" is the final state of many stable RFCs; see a list at [1], and compare it to the (much shorter) list of finished standards above it. The name is kind of misleading these days. Some discussion at [2]. Just to give an example, the base64 RFC 4648 is also a "proposed standard".

[1] https://www.rfc-editor.org/standards#PS

[2] https://datatracker.ietf.org/doc/html/rfc7127#section-2

bakkoting··on iTerm2 and AI Hype Overload
API keys are unrelated to the $20/month product, and the keys are pay-as-you-go. The newest model is $15 per million tokens of output, which is to say, you would be extremely hard-pressed to spend $20/month on the API.
bakkoting··on NoTunes is a macOS application that will prevent Apple Music from launching
I wrote one of those! https://github.com/bakkot/MenuBarVolume

I still cannot imagine why Apple decided that you shouldn't have a visible volume indicator in the menu bar when you have headphones connected. I mean, really?

bakkoting··on Flipping Pages: New Linux vulnerability in nf_tables and exploitation techniques
From the patch [1]:

> This reverts commit e0abdadcc6e1. [...] Its not clear to me why this commit was made.

Anyone dug up the history here?

[1] https://lore.kernel.org/all/20240120215012.129529-1-fw@strle...

bakkoting··on Phind-70B: Closing the code quality gap with GPT-4 Turbo while running 4x faster
Physician, heal thyself!

https://www.phind.com/agent?cache=clsxs6doj000wl008yk8wb4k8

It pointed out the lack of alt-text as well as a couple other issues. Some of the suggestions aren't applicable, but it's not bad as a starting point.

bakkoting··on React has grown beyond its original promise and it's causing more harm than good
If we're being pedantic, you also forgot document.all. Which is in fact an infinite collection of values, because document.all is a different object in every frame.
bakkoting··on The Everything NPM Package
It's not common at all. It can happen, but it's very rare. And it's basically never intentional.

In my experience the most common cause of breaking changes is accidentally breaking on older versions of the runtime, because the project is only running tests on the last version or two. Aside from that, the only notable example I can think of in the last year was a pretty subtle bug in what was supposed to be a pure performance optimization in a query language [1]. I think these are pretty representative, and not meaningfully worse than the experience in other languages.

[1] https://github.com/estools/esquery/pull/138

bakkoting··on TC39: Add Object.groupBy and Map.groupBy
A lot of shipped code is effectively unmaintained even on pages which are otherwise being modified, in many cases by relatively non-technical people (a small business owner contracts a webdev to build a page and show them how to update the content, for example).

And in a lot of cases it's not obvious that your code is going to be incompatible. For example the most recent case there was code which was like `function foo(x) { if (x.group) x = x.group; /.../}` where that function was being called with `foo({ group: [...] })` or `foo([...])`. That code breaks if `Array.prototype.group` is added. No one is going to figure that out themselves unless they test on a version of a browser which ships `Array.prototype.group`, and empirically no one does that.

Yes, we could find a way to break fewer pages than flash EOL broke. But even just a handful of pages people actually use is too much. No browser wants to ship an update which will break (to pick a relevant example) the website of the government of Brazil, even if they somehow "ought to have" updated their code before that update. Developers are empirically not going to do that update and browsers are not going to punish the users of the pages of those developers by breaking them.

bakkoting··on TC39: Add Object.groupBy and Map.groupBy
Browsers are much, much better at addressing security issues than Flash or Java applets ever were. There's no comparison. And even if you think that they ought not to have been removed, surely it's clear that the concerns about security for users are a fundamentally different thing than JS developers wanting a different API shape.

As to versioning the language: languages like Rust and Go use editions, which allow them to making breaking changes to syntax but not to the standard library, which is what's being discussed here. Indeed Rust has several deprecated-but-unremovable things in their standard library. Python makes breaking changes to their standard library, and then people's code breaks. C++ requires you to specify the version for the entire program, which isn't viable for JS because pages mix scripts from dozens of authors, which all need to interact and to have a coherent view of the world. Not sure what other language you're thinking of.

The relatively unique object model in JS, and the fact that the standard library consists of ambient properties, also makes it special; it's harder in JS than it would be in a language like Rust to detect use of a particular feature of the standard library.

bakkoting··on TC39: Add Object.groupBy and Map.groupBy
There's a big difference between breaking things because they're relying on impossible-to-secure plugins and breaking things because JavaScript developers want to invoke an API in a slightly different way.

Regarding versioning, see the immediately preceding question in the FAQ.

bakkoting··on TC39: Add Object.groupBy and Map.groupBy
Global iterator type is coming: https://github.com/tc39/proposal-iterator-helpers

But a method named `groupBy` on iterators traditionally means a different thing: https://github.com/tc39/proposal-array-grouping/issues/51#is...

Global iterable type it's too late for, since there's many extant iterables in the language and on the web which don't have it in their prototype chain and can't reasonably be changed.

bakkoting··on TC39: Add Object.groupBy and Map.groupBy
Not gonna happen: https://github.com/tc39/faq?tab=readme-ov-file#why-dont-we-j...

Browsers aren't going to break old pages.

bakkoting··on TC39: Add Object.groupBy and Map.groupBy
No current plans for `keyBy`, and I don't know that it's really that well-motivated. (I am on TC39.)
bakkoting··on TC39: Add Object.groupBy and Map.groupBy
We originally tried to put it on Array.prototype, under multiple different names, and that broke various pages in various ways. So we gave up and had to put it somewhere else. And it's conceptually similar to `fromEntries` - they're both ways of making an object. So the Object constructor was the obvious choice.
bakkoting··on Oxlint – JavaScript linter written in Rust
eslint and typescript are the de-facto static analysis tools for JavaScript. TypeScript isn't extensible. So if you want to do any custom static analysis, you're doing it as a custom eslint plugin.

It might be better to have some other tool to do pluggable static analysis, but the fact is that there isn't one. And eschewing project-specific static analysis entirely would be giving up far too much.

bakkoting··on The Seamless Communication models
It's a property of the model itself.

> Input audio is split into 30-second chunks, converted into a log-Mel spectrogram, and then passed into an encoder.

https://openai.com/research/whisper

bakkoting··on $20k bounty was claimed
I have a PR fixing that specific issue: https://github.com/prettier/prettier/pull/15209

Just needs another maintainer's stamp.

bakkoting··on $20k bounty was claimed
Curly braces are reflected in the AST, parens are not.
bakkoting··on $20k bounty was claimed
I have a PR fixing that: https://github.com/prettier/prettier/pull/15209

Just needs another maintainer's stamp.

bakkoting··on OpenAI releases Whisper v3, new generation open source ASR model
The endpoint was just confusingly named:

> The Whisper v2-large model is currently available through our API with the whisper-1 model name.

https://platform.openai.com/docs/models/whisper

bakkoting··on Mastering DOM manipulation with vanilla JavaScript
A number of these are using older, awkward APIs, when there's nicer native versions now.

For example, "replace an element" is

    ele.parentNode.replaceChild(newEle, ele);
but unless you're targeting Chrome < 54, FF < 49, or Safari < 10, you can just do

    ele.replaceWith(newEle)
`replaceWith` also lets you replace a node with _multiple_ nodes, or with text.

Similarly, "loop over a nodelist" wants you to use array spread and then forEach, instead of just

    for (let ele of nodelist) ...
bakkoting··on Goodbye, Node.js Buffer
Yeah, in your case I think most of the complexity is actually on the ReadableStream side, not the base64 side.

The thing that I'd actually want for your case is either a TransformStream for byte stream <-> base64 stream (which I expect will come eventually, once the simple case gets done; it's also easy in userland [1]), or something which would let you read the entire stream into a single Uint8Array or ArrayBuffer, which is a long-standing suggestion [2].

---

> Why does de-chunking a byte array need to be complicated

Keep in mind the concat proposal is _very_ early. If you think it would be useful to be able to concat Uint8Arrays and have that implicitly concatenate the underlying buffers, [3] is the place to open an issue.

---

> You have made me realize I don't even know what the right venue is to vote on stuff. How should I signal to TC39 that e.g. Array.fromAsync is a good idea?

Unfortunately, it's different places for different things. Streams are not TC39 at all; the right place for suggestions there is in the WHATWG streams repo [4]. Usually there's already an existing issue and you can add your use case as a comment in the relevant issue. TC39 proposals all have their own Github repositories, and you can open a new issue with your use case.

Concrete use cases are much more helpful than just "this is a good idea". Though `fromAsync` in particular everyone agrees is good, and it mostly just needs implementations, which are ongoing; see e.g. [5]. If you _really_ want to advance a stage 3 proposal, you can contribute a PR to Chrome or Firefox with an implementation - but for nontrivial proposals that's usually hard. For TC39 in particular, use cases are only really valuable pre-stage-3 proposals.

[1] https://github.com/lucacasonato/base64_streams/blob/7c4ed815...

[2] https://github.com/whatwg/streams/issues/1019

[3] https://github.com/jasnell/proposal-zero-copy-arraybuffer-li...

[4] https://github.com/whatwg/streams

[5] https://bugs.chromium.org/p/v8/issues/detail?id=13321

bakkoting··on Goodbye, Node.js Buffer
This specific proposal will only really help with the last part - it will let you write

    return `data:application/octet-stream;base64,${(value as Uint8Array).toBase64()}`;
but you'll still have to do the work of reading the stream to a buffer yourself.

There is a _very_ early stage (as in, it's literally just an idea one person had, which may never happen) proposal [1] to do zero-copy ArrayBuffer concatenation, which would further simplify this - once you'd collected the chunks you could `value = new Uint8Array(ArrayBuffer.of(chunks.map(chunk => chunk.buffer))` instead of manual concatenation.

Finally, there's the Array.fromAsync proposal [2] and/or async iterator helpers proposal [3] (which I am also working on), which would make it easier to collect the chunks. Putting these together, you'd get something like

    if (isReadableStream<Uint8Array>(value)) {
      const chunks = await Array.fromAsync(value);

      if (chunks[0].byteLength) {
        value = new Uint8Array(ArrayBuffer.of(...chunks.map(chunk => chunk.buffer)));
      } else {
        throw new Error(`Unrecognized readable stream type: ${ chunks[0].constructor.name }`);
      }
    }

    return  `data:application/octet-stream;base64,${(value as Uint8Array).toBase64()}`;
    

[1] https://github.com/jasnell/proposal-zero-copy-arraybuffer-li...

[2] https://github.com/tc39/proposal-array-from-async

[3] https://github.com/tc39/proposal-async-iterator-helpers

bakkoting··on Goodbye, Node.js Buffer
Nit: "fixed-length" is no longer true as of very recently [1].

[1] https://github.com/tc39/proposal-resizablearraybuffer

← PreviousPage 3 of 5Next →