I feel like the toy examples in the article might only make sense to people who already know why they want this feature. The examples don't make it at all obvious to me why I would want this feature. The new version in the examples have more code, more indirection, and more magic (in the sense that it relies directly on a specific property of the runtime). Could anyone here help me understand a more robust example where `try...finally` just won't work (or at least would be patently less readable/etc)?

The verbosity comes because they are demonstrating both how to write the library code to support the feature, and how to consume it. But in reality a lot of the time someone else will have written the library code for you.

In this (still contrived) example, we end up having to do nested try/finally blocks.

Before:

  let totalSize = 0;
  let fileListHandle;
  try {
    fileListHandle = await open("file-list.txt", "r");

    for await (const line of fileListHandle.readLines()) {
      let lineFileHandle;
      try {
        lineFileHandle = await open(lineFileHandle, "r");
        totalSize += await lineFileHandle.read().bytesRead;
      } finally {
        await lineFileHandle?.close();
      }
    }
  } finally {
    await fileListHandle?.close();
  }
  console.log(totalSize);
After:

  let totalSize = 0;

  try {
    await using fileListHandle = getFileHandle("file-list.txt", "r");

    for await (const line of fileListHandle.readLines()) {
      await using lineFileHandle = getFileHandle(lineFileHandle, "r");
      totalSize += await lineFileHandle.read().bytesRead;
    }
  }
  console.log(totalSize);

I wonder now if React / Vue / Svelte / SolidJs (and all the others) could use this to cleanup things as a finer grained way of handling unmounting of nodes, for example

Not likely. This is essentially syntactic sugar for `try ... finally`, the resource disposal is scope based. Node unmounting is linked to a different (longer) lifetime system than plain javascript scope.

It’s possible that there are UI systems where this would work but not the ones you listed above.

Yeah, the scope-based disposal jumped out at me from the examples. I suppose that means that anywhere you still have a reference to the resource alive, referenced by an object in the main node loop, that thing would never be automatically destroyed, right? You'd have to manually release it anyway. On the other hand, does this trigger if anything returned from that function goes out of scope? Or not until everything returned from it does?

I think you’re confusing scope and reachability. Maintaining a reference to an object has nothing to with whether or when it’s disposed in this TC39 language enhancement. Such a system _does_ exist in Object finalizers, but it’s hard to use correctly, especially in a language where it’s very easy to inadvertently retain references via closures. Resource disposal of this type needs to be much more predictable and can’t be left to the whims of the runtime. The docs on finalizers and WeakRefs are full of warnings not to expect them to be predictable or reliable.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...

With this new using syntax, resources are disposed of when the object they are tied to goes out of _lexical scope_, which doesn’t need to worry about the runtime or object lifetimes at all. This example from the TC39 proposal makes it pretty clear:

    function * g() {
      using handle = acquireFileHandle(); // block-scoped critical resource
    } // cleanup

    {
      using obj = g(); // block-scoped declaration
      const r = obj.next();
    } // calls finally blocks in `g`
https://github.com/tc39/proposal-explicit-resource-managemen...