tc39 / proposal-explicit-resource-management

ECMAScript Explicit Resource Management
https://arai-a.github.io/ecma262-compare/?pr=3000
BSD 3-Clause "New" or "Revised" License
758 stars 30 forks source link

Need some explanations for that explicit vs implicit thing #212

Closed yw662 closed 8 months ago

yw662 commented 8 months ago

I am just wondering sth like...

Will [Symbol.dispose] be called when an object is about to be collected, if the user failed to do so ?

If so, that [Symbol.dispose] should be an "implicit resource management" tool, and listed there. And this about fixing the "forever pending promises" issue.

Could [Symbol.dispose] be called twice if it is explicitly called ?

This is about preventing "double free" issue. Or, should a disposed object even set itself to nullish, or put itself into a special "disposed" state ?

ljharb commented 8 months ago

No, if you fail to “using” it, it won’t be disposed.

I believe the symbol dispose method is responsible for ensuring that calling it twice won’t cause problems.

rbuckton commented 8 months ago

This is covered in the explainer, but to summarize:

Another way to think of this is:

Will [Symbol.dispose] be called when an object is about to be collected, if the user failed to do so ?

As @ljharb said, [Symbol.dispose] will only be called at the end of the block as long as you explicitly mark it with using. The GC will not call [Symbol.dispose] implicitly during clean up, as there would no longer been an object reference to call it on.

Could [Symbol.dispose] be called twice if it is explicitly called ?

Yes, and it is recommended that implementers of disposable objects should guard against this, if necessary for their implementations. It is not enforced as there are a number of valid use cases for reusable disposable objects, such as object pools and high-performance, low-overhead tracing. Built-ins like DisposableStack and AsyncDisposableStack also explicitly guard against double-dispose.

Or, should a disposed object even set itself to nullish, or put itself into a special "disposed" state ?

As I said, authors of Disposable objects can maintain their own "disposed" state. We discussed somehow giving the binding itself TDZ, but this was ultimately rejected due to implementer concerns, amongst other factors.

yw662 commented 8 months ago

Then some other questions here, the first one is about the "forever pending promises" issue:

I can think of a combination of FinalizationRegistry and Symbol.dispose to dispose the resource both explicitly and implicitly. However, for those who want to enforce explicit resource management:

ljharb commented 8 months ago

@yw662 there's no "detection" whatsoever - that would be implicit. You have to explicitly using something if you want it disposed.

Via a DisposableStack, using syntax may not be involved at all, so it would not be possible or make sense to have any syntax like you're suggesting.

yw662 commented 8 months ago

@ljharb

implicit. You have to explicitly using something if you want it disposed.

eg.

async function foo(){
    using bar = baz()
    await new Promise(()=>{})
}

There is a "using" but it may not just work this way.

ljharb commented 8 months ago

@yw662 that "uses" baz(). promises aren't disposable, and await new Promise(() => {}) is like an infinite loop - i would expect the thing to never dispose.