3 ms·
This seems error-prone, for at least two reasons: * If you accidentally use `let` or `const` instead of `using`, everything will work but silently leak resourc
by creata 1y ago
This seems error-prone, for at least two reasons:
* If you accidentally use `let` or `const` instead of `using`, everything will work but silently leak resources.
* Objects that contain resources need to manually define `dispose` and call it on their children. Forgetting to do so will lead to resource leaks.
It looks like defer dressed up to resemble RAII.
- akdor1154 1y agoThere is pretty strong precedent for this design over in .NET land - if it was awful or notably inferior to `defer` I'm sure the Chrome engineering team would have taken notice.
- creata 1y agoC# has the advantage of being a typed language, which allows compilers and IDEs to warn in the circumstances I mentioned. JavaScript isn't a typed language, which limits the potential for such warnings. Anyway, I didn't say it was "inferior to defer", I said that it seemed more error-prone than RAII in languages like Rust and C++. Edit: Sorry if I'm horribly wrong (I don't use C#) but the relevant code analysis rules look like CA2000 and CA2213.
- masklinn 1y ago> Anyway, I didn't say it was "inferior to defer", I said that it seemed more error-prone than RAII in languages like Rust and C++. It is, but RAII really isn't an option if you have an advanced GC, as it is lifetime-based and requires deterministic destruction of individual objects, and much of the performance of an advanced GC comes from not doing that. Most GC'd language have some sort of finalizers (so does javascript: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/FinalizationRegistry https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...) but those are unreliable and often have subtle footguns when used for cleanup.
- legulere 1y agoIt’s still difficult to get right in cases where you hold a disposable as a member. Its not obvious if disposables passed in also get disposed and what’s right depends on the situation (think a string based TextWriter getting passed in a byte-based Stream) and you will need to handle double disposes. Further C# has destructors that get used as a last resort effort on native resources like file descriptors.
- creata 1y ago> Further C# has destructors that get used as a last resort effort on native resources like file descriptors. True, I was going to mention that, but I saw that JS also has "finalization registries", which seem to provide finalizer support in JS, so I figured it wasn't a fundamental difference.
- electroly 1y agoAs a practical matter it's easy to forget in C# and it's up to you to remember. Those two analyzers are disabled by default and prone to both false positives and false negatives. They hardcoded the known behavior of a bunch of .NET classes to get it to be usable at all.
- deleted 1y ago[deleted]
- akoboldfrying 1y agoExactly this. No idea why you were downvoted. The problem they are trying to solve is that the programmer could forget to wrap an object creation with try. But their solution is just kicking the can down the road, because now the programmer could forget to write "using"! I was thinking that a much better solution would be to simply add a no-op default implementation of dispose(), and call it whenever any object hits end-of-scope with refcount=1, and drop the "using" keyword entirely, since that way programmers couldn't forget to write "using". But then I remembered that JavaScript doesn't have refcounts, and we can't assume that function calls to which the object has been passed have not kept references to it, expecting it to still exist in its undisposed state later. OTOH, if there really is no "nice" solution to detecting this kind of "escape", it means that, under the new system, writing "using" must be dangerous -- it can lead to dispose() being called when some function call stored a reference to the object somewhere, expecting it to still exist in its undisposed state later.
- mistercow 1y agoAnother point there is that JS has always gone to great lengths not to expose the GC in any way. For example, you can’t enumerate a WeakSet, because that would cause behavior to be GC dependent. Calling dispose when an object is collected would very explicitly cause the GC to have semantic effects, and I think that goes strongly against the JS philosophy.
- masklinn 1y agoFinalizationRegistry was added, like, 5 years ago.
- rafram 1y agoFinalizers aren’t destructors. The finalizer doesn’t get access to the object being GC’d, for one. But even more crucially, the spec allows the engine to call your finalizer anywhere between long after the object has been GC’d, and never. They’re basically a nice convenience for noncritical resource cleanup. You can’t rely on them.
- demurgos 1y agoWhat you describe is already the status quo today. This proposal is still a big improvement as it makes resource management less error prone when you're aware to use it and _standardizes the mechanism through the symbol_. This enables tooling to lint for the situations you're describing based on type information.
- 0xfffafaCrash 1y agoHere’s some relevant discussion about some of the footguns: https://github.com/typescript-eslint/typescript-eslint/issues/7160 https://github.com/typescript-eslint/typescript-eslint/issue... https://github.com/tc39/proposal-explicit-resource-management/issues/159 https://github.com/tc39/proposal-explicit-resource-managemen... I imagine there will eventually be lint rules for this somewhere and many of those using such a modern feature are likely to be using static analysis via eslint to help mitigate the risks here, but until it’s more established and understood and lint rules are fleshed out and widely adopted, there is risk here for sure. https://github.com/typescript-eslint/typescript-eslint/issues/8255 https://github.com/typescript-eslint/typescript-eslint/issue... To me it seems a bit like popular lint libraries just going ahead and adding the rule would make a big difference here