Closed yw662 closed 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.
This is covered in the explainer, but to summarize:
FinalizationRegistry
to observe this cleanup for resource management tasks, but you are still at the mercy of when the GC runs and the potential for leaked references.obj.close()
or obj[Symbol.dispose]()
, or a declarative boundary such as using
plus its surrounding block scope.Another way to think of this is:
[Symbol.dispose]()
to explicitly perform cleanup.using
to give the object an explicit lifetime bounded by the containing block scope.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.
Then some other questions here, the first one is about the "forever pending promises" issue:
using
block scope be able to detect awaiting forever pending promises inside ?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:
new.target
for using
, eg. using.target
, for the callee to detect whether explicit resource management is used or not ?@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.
@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.
@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.
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 ?