New Keyword "using" in JavaScript!
Вставка
- Опубліковано 31 лип 2024
- Recorded live on twitch, GET IN
/ theprimeagen
MY MAIN YT CHANNEL: Has well edited engineering videos
/ theprimeagen
Discord
/ discord
Have something for me to read or react to?: / theprimeagenreact - Наука та технологія
React on the server is going to look lit
"use using"
using using = use(use)
Finally, IDisposable in JS
Yeah it's effectively a copy of IDisposable (C#) and AutoClosable (Java)
Just syntactic sugar for calling a close/dispose function on recourses.
It's IAsyncDisposable
Next thing they will copy is IAsyncEnumrable
Naming interfaces with ISomething should be a crime
@@andrebrait why is that so?
Also, I'd much prefer something like python's `with`, creating a new context where the disposal will happen once the context is exited, rather than changing the current context.
with already exist in JS and it's garbage that should never be used.
It turn an object into variables in a scope.
Or Java's try-with-resources.
@@vukkulvar9769 so it's like jai's "using", lol. Jai uses that so you can do "inheritence" without inheriting in the polymorphic sense
@@notuxnobux Or PHP "extract".
@@Yay295 that's Microsoft bringing c# syntax into JS world (if I uderstand correctly it would have same syntax in JS like in this example with TS)
Us C# devs have been using the "using" keyword for a while now
Yeah multiple things in JS have been inspired by C#. Arrow function syntax and async come to mind.
I think they explicitly mention C# in the section where they mention prior art when proposing some of these features.
@@kebien6020 and C# got async/await from F#.
Shhh - He hates c# - I don't think he realises how good it is.
Finally, someone addresses the silliness with using arrow functions to make a named function!
Fully with you on this one. The feature itself is great, but the syntax is weird. I wonder if they just didn't want to introduce yet another keyword along with "using", and thus reused "await".
I can already see beginners getting utterly confused by this.
Feels like that to me. Though they could have used `async using`.
Should have reused async then
The problem is needing to call it.
If it was only.
await using something = resource;
With no call it would be better. There's no call, nothing is happening except the promise construction. Which is stupid.
C# doesn't work like that.
Nah it actually also await the creator function, which makes it fine to me.
async using or using await would be better
Arrow functions are great for callbacks. But for other functions, I prefer the 'function' way.
I even have a vim macro defined for js/ts files. It expands 'ff' to 'function' :)
It's also not a drop-in replacement for a function declaration, as anybody who tried referencing 'this' in the function body would find out real quick.
My issue with arrow functions is that as Prime mentioned. They're not named, all anonymous and every time it's called actually creates a new copy of the same function. Generally it's fine for callbacks.
@@oblivion_2852 Wait, is it true that a new copy is created whenever it's called? That's wasteful
@@NphiniT I'd like to know this as well, this sounds incorrect but what do I know
@@BigBahss I did not find anything to that effect. I'd take that with a mountain of salt
C# makes more sense:
await using (var resource = useSomething())
{
// block to do something with resource
} // gets cleaned up
Can have nested using blocks easily and can read left to right top to bottom.
Similar to python’s with statement/block
Exactly and if scope of using and function ends in the same place you can simplify brackets but it was added later and most of C# devs knows the origins
thats because the C# community isnt full of people with late stage autism like the javascript community
Doesn't C# also has await using? I'm pretty sure i've used it before without a {} block, and it is not clear where in code actually disposes the resource. At least in C# we can use it with a code block between { }, makes it way more clear than letting the compiler "guess" where to dispose.
@@tiagosutter8821
It has, in general I'm not a great fan of await using, but using alone is great and I understand the necessity of having an await version
@@tiagosutter8821 The compiler doesn't "guess". It disposes it at the end of the scope. If there are multiple usings, they get disposed in reverse order.
Also, `await using` was introduced in C# because of async enumerators. Does JS have async enumerators?
Regarding performance of ad-hoc objects versus class instances. There is a real and surprisingly high cost of long prototype chains, and ad-hoc objects tend to be 2-layer (instance + Object.prototype) while class instances are at least 3 layers (instance + class.prototype + object.prototype). You probably aren't going to get a concerning performance hit at 3 levels, but frankly you aren't going to get a concerning performance hit with a new closure for existing function code. And the prototype chain hit comes from referencing properties throughout the object's lifetime, where the closure hit happens only when the object is created.
Arrow functions are good to prevent use of 'new' with the function. An interface should only be able to be used in one fashion, and it should immediately fail if used in any other way. Using 'class' for constructors requires 'new' and using arrow or class/object methods will throw an error with 'new'. The arrow syntax might be ugly, but there's a reason to never ever ever use a 'function' keyword as they can be invoked either way, and unless you boilerplate your functions with a crapton of guards you might end up with strange results if you used the incorrect invocation.
I agree that the syntax for this proposal is godawful. It's getting awfully close to magic, which is the worst feature of any language. Take it from a guy who still has to maintain ancient Perl scripts. Programming magic is designed to make it easier for the first programmer to write, but it makes it much much harder for the second programmer to trace and maintain.
Are you for real my guy?
I think what would make it less confusing for Prime is to make it "async using resource = getResource()" instead of "await using resource = getResource()", because "await" usually means right now and "async" mean that this has something to do with "await"
Yes this is what I was thinking as well. I’ll get used to await, but I think Async would have been more clear right from the start
I had this thought initially, and then I wondered if people would confuse it with async functions.
@@disguysn well, python for example had "async for" for ages. keyword "async" just says that it is asynchronous, while "await" implies some waiting
they copied C#
If you look at the DB example, turns out that the creator function can also be async (and most of the time when you have an async dispose you'll have an async creator). You're actually awaiting the creator function, which means it's not as bad.
The main diference between ()=>{} and function(){} is that the first can excute in the global scope and access it's variables, when inside a class or an object. The function declaration, runs inside the local scope of the object and canot access the values from where it was called, this comes from vanila JS, in frameworks this does not make a diference, it's only visual.
In V8 (via `deno bench`) function that return object with accessor (get/set keyword) will take more time than class { get value() {} }. Also same rule apply with methods.
I agree that the syntax is weird. I think that they are trying to prevent nesting in the resource scopes and bind their usefulness to the parent function scope
I initially thought that it would be like how it works in C#. But it is very different.
Maybe it is something that is supposed to be used in factory pattern. Create a factory for file handle, and use to to get a safe file object from it.
I learned something new thanks!. And on top of it a nice rant as always xD
Naively I would assume that calling a method on a class instance that uses a field would be slower than calling a method on such an object using a variable in the closure. To call the method you need two hashtable lookups, one directly on the object, which fails, then going one up the prototype chain. Then you need another hashtable lookup for the involved field. For the object+closure case you need only one lookup for the method and the variable is bound via closure. That should be accessible via a pointer deref and array element access, basically. However, any of that could be optimized in any way and it ignores the added GC pressure for creating a closure for each method.
You forgot var keyword can override arguments. So you might still need 2 lookups.😅
@@alalalavaladu3670 Pretty sure arguments just like locals and closed over variables aren't looked up via a hashtable. The parser can already disambiguate what is meant lexically at parse time and just generate the correct reference (pointer/array index).
3:08 the reason, I think, why arrow function are preferred over function declaration is that the arrow functions in JS don’t redefine the value of “this” in their function body which makes them more “stateless”
That might make sense if they were actually using the “this” value, but generally they don’t.
@@calebvear7381 The overhead exists, whether 'this' is used or not. Also, arrow functions don't get an 'arguments' object, another source of overhead.
@@grumpylibrarianno overhead if you don't use this and arguments and eval
Ah! Excellent point! Still, I laughed my butt off & agree with Prime's (hilarious) frustration.
the functional / stateless programming community has literally taken over javscript now. its too far gone at this point
Honestly I like the await using syntax, as it'll also await the getResource() call. If not going with this, I think we'd need two keywords, which would end up in something like "defer using resource = await getResource()".
Totally agree. Will be nice to have but the syntax is needlessly confusing.
Waiting to get defer, oop destructors, free() possibly and maybe like a referencing counting thingy that interacts with all of these features.
The arrow function thing is basically because the standard is to treat function as values (assigning them to variables, passing them to other functions, etc) instead declarations. It's just a matter of perspective and getting used to it. I personally prefer that style, but yeah a lot of people prefer declarations.
As for the `using` feature... I guess it's fine for some use cases, but I feel like it just doesn't belong to JS.
why would I ever want a function to be a value / variable? lol the whole point of a function is its a definition you pass variables in to... it seems this whole functional programming community has late stage autism
I know people throw around phrases like "LOL", but when you described (at ~ 2:50) how much you hate that try-hard style of arrow functions instead of a function call with an empty parameter list - I laughed my f**king ass off. Perfect! 😂😂😂
After writing Javascript for 11 years, I'm finally ready to be off this ride. There's only so much wonky syntax I can learn year after year. I'm gonna go learn Rust.
Don't tell him boys
I recommend go
@@deado7282 I recommend Rust
@@Tigregalisfrom one branded frying pan to another branded frying pan
@@supIMJohnFaulkner I might try Go as well. JS isn't the only language I've ever used, I've written Java, Python, Obj-C, and a very little bit of Swift. But frontend has been my jam for the longest time. I'm just too tired to keep up with the constant changes, and the fact that it's building on top of bad design choices from 20 years ago. I just need something new.
Would love to see a class vs object test. We'd definitely see some unexpected results
This file handle thing would peibably work well for libraries, but otherwise I think I prefer the older code style. Surely, if you remember to use using and create the fn for it plus the dispose fn, you would remember to close the handle.
agreed. seems like it's designed purely for library developers.
There was a lot of pressure in the committee to use “using async” instead of “await using” but there were issues with the language parser complexity or backwards compatibility or something.
What they might should have done instead: add a using statement that simply invokes GC for the specified vars at the end of the block. In addition to closing file and network handles as soon as possible, this could have been used to explicitly free other large data structures, large array, long strings, etc. - much simpler to understand and likely would have solved a lot more resource deallocation problems.
Typescript is blatantly copying C# features these days. 😂
And i'm all for it. Cause it's awesome.
Because typescript is microsoft..
Destructors are C++. Other languages (except those also designed correctly with them in mind from the beginning, like Rust) just keep having to find kludges to imitate them, including C# and now JS.
We C# now
TypeScript is just c# for the most part with out saying it out loud. You know there is a namespace keyword in TypeScript.
@@FilipCordasthat for JS
C++
The trend of languages without RAII coming up with kludges to imitate RAII remains undefeated
The syntax/semantics is too outrageous
`using async resource = ` would make the most sense, followed by `using await resource = `
Defer *is* more flexible, but it's an extra statement.
I converted a small custom vuejs with typescript library from class to defineComponent and the compile time was significantly worse as defineComponent
0:31 No it's like using ... from C#.
By leaves scope it depends on how they have implemented it. In C# its either the scope in which it was declared or its explicitly scoped using curly braces.
i.e. using (var someResource = new Resource())
{
...
} // Disposes here
Or
public void MyEnclosingMethod()
{
using var someResource = new Resource();
....
} // Disposes here
3:17 FP zealotry but I agree. It's dumb with a capital stupid.
7:48 isn't the point that it's dealing with unmanaged memory? Thats what its for. i.e. if you didnt close it it would be a memory leak.
"No it's like using ... from C#."
Destructors, from C++.
@@isodoubIet No it's not. C# has destructors. This is not not at all that (because C# and JS are managed languages and this is a pattern for dealing with unmanaged code).
@@sacredgeometry "C# has destructors"
They're not the same as C++ destructors because the latter are _deterministically_ called at the end of scope, and IDisposable is just a hack to imitate that behavior.
@@isodoubIet I know that was exactly the point I was making. C# and JS dont have C++ style destruction and the pattern they are using to dispose of unmanaged memory is the dispose pattern.
Which was directly borrowed from C# and is in use now in JS.
It has nothing to do with C++ destructors. It isnt a hack to imitate that behaviour. Its a pattern to implement it.
this is basically `with` from python
but much worse
I don't think so
Context Manager in Python is really smoth, readable and easy to use. This crap in JS give you more worries than profits
it's more like defer in Go
@@Amejonah not really. a defer runs anything u mark as defer at the end of a block. this is like python's context manager where the one creating the class/type defines what happens at the end of the block and you're merely a user of it, you're not exposed directly to what is going on underneath
I would like to have a way to trigger garbage collector manually. It will be useful...
I thought this would be a great idea, but testing this on 5.2beta, it's only seems to be lexical scope. :( pass this object into a closure and it will dispose at the end of lexical scope no matter if your closure still has a reference. This part of `using` really needs highlighting in Docs, because scope is not just lexical. Because of this limitation your not getting much more than a `try / finally`, only benefit I can see is that your dispose can be defined up-front, and you save 1 level of code indent. TS docs correction -> function when it leaves lexical scope.
What would have been great is `[Symbol.dispose]` directly with `Object`?, no need for `using` in the first place. I assume the reason is that it requires low level JS integration to do this, not something Typescript could polyfill or transpile. And because JS is in so many Browsers / Backend it would take a while before becoming mainstream, but this is something Ecmascript should have pushed years ago, if they had it's likely it would now have been mainstream among JS Engines.
I assume it is still something I'll use, but just have to be aware that all code inside using will need awaiting, and don't pass this object into a none awaited closure as the dispose could get called before the closure is done.
setTimeout(() => db.clean(), 1000); //BOOM!!.. DB closed, you plonker!!..
C# has this for years. Blazor baby!!!
It does make sense he doesn’t like it.
The functionality is nice, the way to use it is annoying.
The `using` key is also changing the known meaning of `await`. IMO the way it just respects the scope is hidden magic. It’d prob be more interesting if it created a scope
I feel like these features are asynchronously disposing my remaining brain cells.
"like deconstructors in javascript"
Ah a new baby! Oh no, its deficient. *Throws baby in the dumpster*
I appreciate that you bagged on the symbols in js arrow functions. It drove me nuts when I was coming from python and now I'm just comfortably numb.
In C#, the IDisposable interface has existed since version 1.0, and is understood by the compiler, so that when you implement IDisposable, and have the Dispose method defined, it's automatically called. This... look like a pain to set up in JavaScript. The try/finally code is MUCH simpler, with far fewer lines of code. I'd be curious about the performance of the using pattern her vs. using try/finally.
I had a dream that Prime was on the Lex Fridman podcast.
Fwiw, defer is probably my favorite keyword/feature of Go.
6:46 is the same as just using a callback. I guess the whole point is that you can defer (or await using) many resources in the same scope. So when scope is done, all of them are unloaded at the same time. Am I getting this right?
All this can be done with Promise.all and a bit of structure...
3:24 yes!! I wonder the same thing all the time.
don't forget, you can also use these in async context
people assigning an anonymous function to a variable is also a pet peeve of mine.
If you want a named function, use a named function. If you want an anonymous function, use an anonymous function. Don't mix and match.
This is like python's context managers... but way less clear😂
please remember that JavaScript is a modular language that oaradigms the DOM from a JAVA engine that runs the API of the browser.
You programmers that are matriculated out of college needed a Object Oriented Programming syntax so you can feel better about all the student loans and years you didnt need to be in a classroom… Typescript is the result to help you adjust to the paradigm of this… Because the new paradigm of software development lives in the web and cloud. Thus companies are not waiting on solutions that are JAVA or C# which have expensive life cycles and are higly depend on the Client Object Model of an OS
i am happy i went to college
i went to a state college
i lived in said state
i paid 3600/y (at the highest, it was 2700 when i started)
checkmate, atheist
suggestions for more cool JavaScript keywords:
`def exception { .... }` - run the code in { ... } and ignores (DEFies) the exceptions.
`class X mut Y` - declares that X and Y have some MUTual attributes.
Sounds like the with keyword in python aka a context manager
Also to answer your question.
My guess is Yes its like calling another awaited function call at the tail of the enclosing function scope.
it is like javascript imports "import {some} from file" instead of "from file import {some}" when they designed it they did not think about ease of use.
With each JS feature it's getting more confusing... And I am 7 years into it. Can't wait for this feature to get into production and mess GC even more.
Wish we could just be more explicit and not hide even more abstractions under some implicit behaviours which you need to know because there is no compiler for you to catch that and say you are going a little crazy.
That's why I went from JS to Rust with WASM for webapps. Same runtime, but compile-time errors and real typechecking.
This has nothing to do with GC, you are confused
@@Mike-uk2oq Yes and no. From my understanding of this now, this will invoke once object is going outside of scope, so being deallocated by GC sometime later + I can imagine that someone will gladly use such location for strange behaviours
@@ichizos9615 It just calls the dispose method at the end of the scope. The GC is not necessary here.
@@Mike-uk2oq Yea you are right, I was clearly confused here.
I think I'm beginning to agree more and more with Crockford about js
I always thought that when looking at JS, I’m a C# developer, I always wondered why in JS all functions seemed to be defined as lambda functions when they didn’t need to be, as if the writer of the function was showing off, but didn’t understand the when and where the feature they was using was supposed to be used. In-line code becomes unreadable when abused
thats because the JS community has been taken over by people with late stage autism
Totally unreadable... Congrats JS devs, you have created a new crap
In the `const fnName = () => {}` vs `function fnName() {} ` debate, if I can give my 2 cents, function declaration are affected by hosting (declare before the file start executing; can't be set conditionally) and bind to the function or global scope. The cost syntaxe is less "surprising"
I did testing, object itself are much faster than classes, if you have a factory function, is also much faster than a class... but classes create instances with many prototypes faster... also you can create yourself a prototype function so it's like meh... class is much cleaner... if you do like idk GreenSocks GSAP animations and using Classes for flying animated shit is probably much slower than using prototypes and creating object with a factory function.
Do you have an example code?
Thank you.
What kind of keyboard switches are you using?
What if I store it somewhere else? Does it dispose twice?
What is the best language feature for resource disposal?
1. using (C#, JavaScript), AKA with (Python)
2. defer (Go, Zig)
3. RAII (C++, Rust)
4. goto (C)
RAII best.
'with' in Python is really nice
Defer ain't specifically for resource disposal, it could also be used for logging and shit.
that's like asking what's 7+3
third option
@@JuvStudios I agree but I wish I understood the historical context in which someone invented the phrase "Resource Acquisition Is Initialization", because any time anyone actually refers to it, they're referring to the opposite concept "releasing resources when leaving scope". it's the best feature with the worst name.
i agree with you, my eyes are twitching every time i see an arrow function. i think regular function is semantically better. because it says function not const, like why?
Defer isn't the most appropriate word due to the implicit try/finally. Using is a great word choice since many other languages "use" it.
You can probably also add a block scope to using with braces? In C# you have both options and trust me, it's way better without the extra braces if you can get away without them.
"The GC doesn't close the file handle?" Oh man, we've found the source of the leaks :D
I am generally against all forms of "syntactic sugar"
I agree, I love `defer`
I love that JavaScript is being written as functional with scopes, if you look at all of the examples, you need scope to use using. JavaScript has always allowed wrapping everything in curly brackets to give scope without needing classes or namespaces, and these examples show that in action. I would prefer if using was a class or even a keyword of “resource” to denote the intention of the code without having to look at the object members to see if dispose is being used. So, take the current class format and replace the “class” keyword with “resource” and this specification would be much clearer and easier to understand.
Also, I am not a fan of using “Symbol” to add functionality to the language instead of keywords. The Symbol documentation will have a lot of links or end up being the longest page with unrelated content.
Wait why do you need to do all this sh*t wont the object get removed when it goes out of scope anyway?
Defer is preferred
Will I be using this? Let's await and see!
Ill see myself out
So my understanding at 5m is they are implementing defer like Go but worse.
@ThePrimeTime apparently you don't have a shortcut for inverting position of two adjacent characters
Which software you use to record your video
If you use "using", you kind of already need to know that something will happen when leaving the scope... the "using" statement is "deferring" to the end of scope so to speak... If you look at it like this, the "async using" feels natural... it's deferring an async operation to the end of the scope in stead of a non-async one.
a parenthesee
New keyword dropped boys
this one developer at my company has autism and told me to always use const and never use var. and he said classes are toxic and to always make everything a functional component and use arrow functions for everything... after debugging one of his 50 layer deep arrow functions I switched back to classes
Yeah, and pattern matching is still Stage 1 proposal
looks like golang's defer
USING DEEZ
Sounds like it was lifted directly from C#
I see the future of all programming languages...
Over time every enthusiast of every programming language will get their favourite features of whatever language they love into JavaScript. Why? Because eventually they have to do some web development, they find they have to use JS instead of their favourite language, but Javascript is shit for them, so they push to make it look more like what they know and love.
I first had this thought when JS sprouted the unnecessary "class" feature. Ah, I thought, a lot of refugee Java programmers have been forced to use JS, they want to make JS look like Java. All of a sudden the innocent simplicity of JS was defiled, sullied.
Of course bolting syntax and semantics of one language into another results in a chaotic, unfathomable mess. We see this with natural languages like English. Concocted as it was from old Viking, old French, old German, Latin, and other influences as it is, and then bent out of shape by Americans. I'm sure there is an "original English" still in there somewhere.
Of course this processes of language rotting is not confined to just JS. Look at what has happened to C++ as every idea from every other languages is injected into it, as it flails around pretending to be a functional language rather than an OOP language, etc.
No, every language we have will get stirred up by every possible feature from every other language.
Entropy always increases as the Physicists tell us. The heat death of programming as we descend into chaos, unable to do anything.
javascript has been taken over by people with late stage autism. anyone who is actually making useful apps prefers oop patters, stateful programming, classes... the only people who want all this stateless, function / declarative programming have late stage autism that can never be cured.
Bro just stop with all the drama already
Fart
@@diadetediotedio6918 Hei, Bro, Dude, my man, hope you don't mind my hint of drama. But I do believe there is a rather large pinch of reality in what I have said.
C# does it exactly the way you prefer Prime. Every day I get more and more impressed with the C# community, its packaging system, the CLR speed is close to C code. and its strong typing, and oop nature.
Close to C? Excuse me?
Bill Gates sucker alert
@@gerooq it is close to C in some benchmarks
@@gerooq What made you think that C# can't have C performance?
@@eugenakv not sure honestly
JS keeps on adding stupid (barely used) features but they freaking won't implement a strict type system
It's like Ecma script foundation not even working
On the other hand Dart ( Flutter's language), just see that language's progress. It improved so nicely. It's basically my 2nd fav after Rust
JS is my first language after getting traumatized by Java. I just want it to improve as a language
Typescript is great but pure JS typing is heaven
Use a language with a compilation step, there is no reason not to
Your rant at 3.23 was like me practically every day at work. Why?
This is try-with-resources from Java 8
Yeah, but with worse syntax. It's sad when Java does something better. I say that as someone who actually likes using Java as well.
@@CottidaeSEAnot better than just disposing of it when leaving the scope or dropping it like in Rust
@@JorgetePanete Yeah, but that's really only possible because the compiler knows exactly when it will no longer be accessible. That is just a technical impossibility without rewriting the compiler and in the case of Java, the JVM as well.
A lot of the headaches that exist with resources not being closed are instead built into the language on a fundamental level in Rust. That increases the headache of doing just about anything complex. So there are tradeoffs to consider.
@@CottidaeSEA the headaches are _not_ closing them
@@JorgetePanete Yes, but now you have a whole heap of other things to think about such as lifetimes. It's a tradeoff.
"It feels like the most try hard annoying feature of all time" He says as he try hards his text editor
I also despise using arrow function. function is the way
What do you despise about arrow functions?
Typescript is a fantastic language. Its only downside is its intrinsic ties to Javascript. Someone needs to build a TS only compiler and runtime with its own rules and break free from mother Javascript's teet.
I think TS is trying to "replace" JS but by eating it veeeeery slowly
using vs await using is only different in that it tells which destructor to call at the end of the current scope. Destructors are always called at the end of the current scope where using or await using is used, pun intended.
I hate that you have to manually tell the runtime which destructor to run...
Just like C#
The implementation looks a bit ugly for library builders, but for the user it is easy to understand. Inside the block I have the connection, outside the connection was closed. This is going to help many beginners not to have memory leaks.
The more I write other languages, the more I hate JavaScript
Agree defer sounds better
It was really needed... But I still prefer real RAII because then its not strictly scope-tied, but you can move that out of the scope or put it in variables.
The reason why JS needs this because there are a lot of resources (including native .close() methods when integrating cpp libs)... GC never solved these - RAII and also rust does from the start...
The fun fact is that wih this await bullshit.... they managed to make it tenfolds more complicated than C++ RAII lol (yet less powerful haha)
> but you can move that out of the scope or put it in variables.
would it be possible to still use `[Symbol.dispose]` (without `using`), and e.g. `myResources.push(getResource())`, then later `myResources.pop() // dead_resource`, then when something is released (recovered by the GC?) it would call `dead_resource[Symbol.dispose]()`?
that is, `using` is only syntax sugar for releasing resources in scopes, but `Symbol.dispose` can be called when something is released?
@@Tigregalis The way it works in C++ is, the object's destructor always gets called at the end of a scope, no matter what (white lie, there are also some optimizations I won't get into but this is the basic mental model). What happens when you, say, store a unique_ptr that owns a resource somewhere, is it'll get _moved_ which transfers the ownership so that when the original unique_ptr gets destroyed, nothing happens. Rust is slightly different because moves are destructive so the original object's destructor won't get called, but conceptually the crucial step is still a move with the associated ownership transfer.
I only know enough javascript to know I want to stay away so people who actually use it are invited to correct me, but I don't think the kind of move semantics that would be required to make sense of this sort of operation even exists in JS.
❤❤
Why are they going the pseudo-destructor route rather than just having an explicit `defer`? The Drop trait makes sense in Rust due to its ownership+lifetime semantics, but does this `using` idea actually make any sense in JS? Why would `defer` be a bad idea? (I know `defer` is kind of already a thing for `` but that's not technically JS at that point).
let resource = getResource();
defer resource.dispose();
// or
defer await resource.dispose();
This is just objectively clearer, even if you have to type an extra-line (oh no, not another line(!) /s). It would work with everything else already too that doesn't have the Symbol.dispose/asyncDispose nonsense too.
Because "defer" doesn't really have use-cases other than destructors. Writing defer line for every resource instead of simply using it is obviously worse.
@@eugenakv I use scope-based `defer` in other languages all the type for many things which are not "destructors" whatsoever. A good example are any calls that are effectively in nature begin/end, open/close, increment/decrement, etc, most of which have nothing to with type construction.
Is it still thenable? They are limiting composability more and more it seems