The Actual Dumbest Thing About Try/Catch

  Рет қаралды 48,729

Theo - t3․gg

Theo - t3․gg

Күн бұрын

Пікірлер: 351
@andrew_ray
@andrew_ray 4 ай бұрын
Try scoping makes perfect sense. You're assuming that your catch block returns or throws. If it doesn't, then there's no guarantee that a value assigned in a try block isn't uninitialized. If your catch block didn't return in the first example, then your function would throw a TypeError because you can't multiply undefined by 2. Thus that line _can_ throw, and so belongs in the try block. Then you can look at the return statement. Unless you want your function to be able to return undefined, then you have an error in your logic. To fix the logic, move the return statement into the try block with its dependencies so that it doesn't run if its dependencies didn't resolve.
@masterflitzer
@masterflitzer 4 ай бұрын
that's why errors as values are just indefinitely better than exceptions and try/catch also if you've watched to the end he discovered that and recognized the scoping makes sense how it is
@dinhero21
@dinhero21 4 ай бұрын
JavaScript can't type error in multiplications, the only way you can error in a multiplication is if one of the factors's prototype's valueOf function throws in the video's case, undefined * 2 is NaN
@gabrielpeleskei3075
@gabrielpeleskei3075 4 ай бұрын
Scoping is necessary and correct. It is plain skill issues. The calculation based on the throwable function must be in the same scope. Putting it outside makes no sense. The design to return errors or throw them is equaliy good or bad. The problem in Javascript is the handling of the function definition (you may not know that a function throws). It could be changed inspired by swift, needing to add a throws section to the function definition if a function actually uses the throw statement. This example tries using try-catch in errors-as-value manner. Just don't!
@masterflitzer
@masterflitzer 4 ай бұрын
@@gabrielpeleskei3075 isn't that exactly what the comment said: "try scoping makes perfect sense"? what additional info does your comment give?
@gabrielpeleskei3075
@gabrielpeleskei3075 4 ай бұрын
@@masterflitzer If you don't see any, that's good with me.
@the-old-channel
@the-old-channel 4 ай бұрын
The real solution to this is to make so that blocks are expressions. So we can do: let double = try { maybeNumber() * 2 } catch { -1 } Rust got it right
@vvvvvvvvvwv
@vvvvvvvvvwv 4 ай бұрын
Yes, or errors should be values
@dzigizord6567
@dzigizord6567 4 ай бұрын
this is the way
@DanKaschel
@DanKaschel 4 ай бұрын
Why is rust so good at everything 😭
@lengors7327
@lengors7327 3 ай бұрын
Was gonna say the same thing, but using Kotlin as an example.
@DASPRiD
@DASPRiD Ай бұрын
Yep, in Rust everything just falls into place, it's just so well designed :D
@christopher-pfeifer
@christopher-pfeifer 4 ай бұрын
Theo must have something against pirates, pronouncing "var" like "vair."
@kettenbach
@kettenbach 4 ай бұрын
verror, vare, vair . I don't car ☝️😃
@ccash3290
@ccash3290 4 ай бұрын
I think it's because var is from variable. I still hate it though
@567legodude
@567legodude 4 ай бұрын
@@ccash3290 and that's why we should all say car as in carriage
4 ай бұрын
@@567legodude I agree with your point and unfortunately that means we both need to pronounce "gif" as "jiff" now
@Bittboy
@Bittboy 4 ай бұрын
Tomato tomato, potato potato 🤷 just the weigh she goes
@shaheennamboori
@shaheennamboori 4 ай бұрын
6:20 Writes a custom error "Forcing var to never get hit" -> Sees the error in the logs -> Interesting that they have "Forcing var to never get hit" error 😂😂😂
@testaccountyt
@testaccountyt 3 ай бұрын
I thought the same thing, Theo has the memory of a goldfish
@comradepeter87
@comradepeter87 4 ай бұрын
My 5 year old son instantly said "Lest some scoped variables could be left in an invalid/indeterminate state!". He's so smart.
@05xpeter
@05xpeter 4 ай бұрын
After my daughter's first day of school. She came home and declared "zero is the first number". I was happy she was on the right team. A week later she asked: "Dad are you sure that if you count long enough you will not get back to zero". I said "yes I'm sure". She wasn't buying it and asked me multiple times. At that point I tried to settle with fact that my daughter probably would become a C-developer.
@milanstevic8424
@milanstevic8424 4 ай бұрын
@@05xpeter In fact you are not sure. There are at least half as many algebras in which counting upward would get one back to zero. This is equally real and possible in mathematics as the infinity you're indoctrinated with. Numbers aren't a physical thing, everything is a convention, and cyclic number systems are arguably even more rigorously defined than infinite sets, especially when it comes to integers.
@05xpeter
@05xpeter 4 ай бұрын
@@milanstevic8424 Yeah there is always the possibility that see could become a mathematician. I guess I though about that when I named her "Tilde", my wife wan't happy when she found out that I had put a math easter egg in her name. But as I told her it had to be "Tilde" I couldn't call her "Line" (that's my wife's name) and "Cirkle" is a little to much.
@Georgggg
@Georgggg 4 ай бұрын
try scope is annoying, but not a big deal.
@567legodude
@567legodude 4 ай бұрын
It would be a strange break of consistency to have one particular block not be scoped. I'm looking at this from the perspective of C-like languages, where just using plain brackets alone serves no other purpose than to introduce scope.
@balduran
@balduran 4 ай бұрын
You can use brackets on their own in javascript too. But I never had a situation where this made sense to me.
@kered13
@kered13 4 ай бұрын
@@balduran It can make sense sometimes in C++ (probably Rust too) by allowing you to use block scope to control the lifetime of objects using RAII. In languages without RAII there is no reason to use it.
@asailijhijr
@asailijhijr 3 ай бұрын
@@balduran I've tried to do it a couple of times, but it threw errors so I gave up, I'll have to revisit it sometime.
@tomnussbaumer
@tomnussbaumer 4 ай бұрын
An additional argument is syntax: when something looks like a block (surrounded by the curly brackets) why shouldn't it be a block? Any language I've used in my decades of coding handles it this way and it makes perfect sense.
@MrTomyCJ
@MrTomyCJ 4 ай бұрын
The idea would be changing the syntax along the scoping behavior, to prevent that consistency issue.
@JeyPeyy
@JeyPeyy 4 ай бұрын
Object literals use curly braces, but they're not a block per se. But I guess it's a bit different when it's an expression rather than a statement, which is usually easy to distinguish
@JoRyGu
@JoRyGu 4 ай бұрын
Theo: "var hoisting behavior is bad" Also Theo: "we should be able to hoist variables outside of try blocks" Makes sense.
@ninocraft1
@ninocraft1 4 ай бұрын
js mind virus take from theo again xD
@386enhanced
@386enhanced 4 ай бұрын
@@ninocraft1 isn't he a React shill
@akam9919
@akam9919 4 ай бұрын
In his defense, I would say that hoisting within a try block is very different than from within a function or a loop.
@JoRyGu
@JoRyGu 4 ай бұрын
@@akam9919 Except that it's completely inconsistent with every other block scoping behavior in JS. Why would you make one single exception? That is setting yourself up for disaster.
@chris7263
@chris7263 4 ай бұрын
As someone in the process of learning js, the fact that var hoists *differently* is what makes me feel a little hysterical.
@Z3rgatul
@Z3rgatul 4 ай бұрын
javascript devs discover in 2024 why try/catch statements create separate scope 🤣🤣🤣 it was designed in this way for Java and C++ for a very good reason. And most likely there was some small unknown language that had the same concept 10+ years before Java was even created
@xenitane
@xenitane 4 ай бұрын
my exact thoughts, like dude that's not a js issue, it's an oop design thing. and as error handling goes, i'm loving how go/rust/zig treat errors as values, much pleasant to work with.
@warrenarnoldmusic
@warrenarnoldmusic 4 ай бұрын
Js devs choose random hills to die on😅
@Bu7MaiD075
@Bu7MaiD075 4 ай бұрын
The reason is memory. It always comes down memory.
@PraiseYeezus
@PraiseYeezus 4 ай бұрын
@@xenitane this has next to nothing to do with oop design lol block scoping (with brackets) comes from C, same place Java and C++ got it from.
@PraiseYeezus
@PraiseYeezus 4 ай бұрын
are you even following the discussion? it's more so about function scope vs. block scope, not scope in general. considering JS has embraced both design paradigms at some point it's not crazy to see some people weigh the pros/cons of both
@jakeleventhal4175
@jakeleventhal4175 4 ай бұрын
blocked scope is the correct implementation. NNN
@adnan7698
@adnan7698 4 ай бұрын
No nut November?
@FurryDanOriginal
@FurryDanOriginal 4 ай бұрын
@@ononaokisama No Nut November
@Daneus_GMD
@Daneus_GMD 4 ай бұрын
bro wrote a community note on a yt video
@brennan123
@brennan123 4 ай бұрын
I've liked Option/Result type of error handling. Especially with exhaustive pattern matching languages. Code is much more transparent on what it can return, increased type safety, and compiler can reason deeper about your code and catch more errors at compile time. Also gives you the lower level primitives to build custom higher level error handling more suited to your particular use case. Having to use `let` outside of the try/catch as a workaround and not being able to use `const` just feels dirty and unnecessarily imperative to me.
@fjjfjfj
@fjjfjfj 4 ай бұрын
I feel like we would all be better programmers if we are forced to deal with error cases, enforced by the types, more often. It would be annoying, and maybe less efficient, but hopefully less breaking stuff :)
@brennan123
@brennan123 4 ай бұрын
@@fjjfjfj Performance is an interesting point. There are probably scenarios where checks can be skipped. There's also scenarios where things like bounds checking of arrays don't need to be performed because the compiler can guarantee it's not empty. There's even ways to create types for non-empty arrays as well. I don't think we're there yet, but I've always wondering if compiler technology improves and we can specify our intent at higher levels, the compilers can make more assumptions about the code and optimize better. Really hard to do with imperative / procedural code though.
@TQuantP
@TQuantP 3 ай бұрын
That'd one extra reason to love golang's errors as values implementation... Everything is so crystal clear because of that! (that and the fact that Go has even less syntactic sugar than C 🤣)
4 ай бұрын
Watch to the end - Theo realizes the scoping in `try {}` is needed after all! I hope Theo pins a comment about this. The problem: while declarations are hoisted in blocks, initializations are not. An error within a try can result in an initialization not being reached; therefore it is control flow.
@sorrynotsorry8224
@sorrynotsorry8224 4 ай бұрын
This is why I've gotten into the habit of moving try-catch blocks into their own functions and use something like Go's pattern (which I really like).
@MrManafon
@MrManafon 4 ай бұрын
This is the correct answer. I took the same pattern from Elixir, where try blocks have a return and their result can be assigned, making them effectively tiny functions with syntax sugar.
@pranav_bhasin
@pranav_bhasin 4 ай бұрын
This is exactly where I prefer the approach that Kotlin takes. It maintains the scoping but allows returns from the evaluated value of the try/catch flow. It would look a bit like the following in JS: const num = try { getNumber(); } catch (e) { console.log(e); return -1 }
@natrixnatrix
@natrixnatrix 4 ай бұрын
The fact that a substantial number of people think that curly braces should sometimes create a new scope and sometimes not is honestly kind of insane to me. The reason var works is not because it hoists but because of inconsistent scoping rules like this. The hoisting part has nothing to do with.
@PedroPedruzzi
@PedroPedruzzi 4 ай бұрын
The main shortcoming of the try catch syntax is that it isn't an expression. In practice it forces the pattern of isolating the block in another function so that one can return something useful in both try and catch blocks. e.g. try { return getUnsafeStuff() } catch (err) { return getAlternativeStuff() } A new expression syntax would help. But I've people using a helper like this: const result = orElse(() => getUnsafeStuff(), err => getAlternativeStuff())
@2547techno
@2547techno 4 ай бұрын
12 minutes of straight yap
@utilyre
@utilyre 4 ай бұрын
This is why people like errors as values. It's not that returning an error is much different than throwing it, but the fact that you only scope the error case outside of the function is what people like.
@vsolyomi
@vsolyomi 4 ай бұрын
"What's control flow?.." - Theo, Aug 2024 :)
@stephenbelanger
@stephenbelanger 4 ай бұрын
If the block scope of the function leaks out of the try then throwing midway through would result in uninitialized variables. With using let outside and reassigning you have an explicit initialization which can be set to a new value if the try succeeds. If you hoist the assignments out you either need var semantics where everything is initialized to undefined at the start of the function and then changed wherever the var statement occurs. Uninitialized state is very unsafe, especially with block-scoped variables as they are initialized at statement position not hoisted to the top of the block, so variable initialization might not be reached and then subsequent code which assumed initialization happened could corrupt memory and crash the process. Unscoped try/catch wouldn’t work the way you think it should.
@ValaSelene
@ValaSelene 4 ай бұрын
I think it's also worth covering that it could also break on the line that does the assignment, but still *before* assignment, depending on what it does. If `const foo = MightThrow()` then `MightThrow()` throwing would occur before assignment as function execution takes place before assignment. I.e. don't think of it as every separate line potentially failing so much as every separate operation within every line.
@Bu7MaiD075
@Bu7MaiD075 4 ай бұрын
javascript devs are too comfortable with changing javascript than themselves
@warrenarnoldmusic
@warrenarnoldmusic 4 ай бұрын
A bug: skill issue Js devs: it must be the language, no it is the browser, no it is the device 💀😅
@DarthVader11912
@DarthVader11912 4 ай бұрын
@@warrenarnoldmusic Nah, it's mostly the rust devs who try out javascript and don't understand a thing.
@mugiseyebrows
@mugiseyebrows 4 ай бұрын
Hot take: that's how things probably should be, any part of computer system should be able to evolve through change (except for null being an object, obviously, that should stay forever this way). Javascript was mediocre before it become good.
@danielt8880
@danielt8880 3 ай бұрын
​@DarthVader11912 yeah right? blame it on rust dev
@theaninova
@theaninova 4 ай бұрын
I don't know why this wasn't brought up, but the solution is absolutely not to have the variable be hoisted, the solution is to have try (and if and other control flow) as an expression. const num = try { getNumber() } catch (e) { return -1; }; const double = num * 2; Rust does this and it's excellent. I don't even think this would interfere with the current JS grammar since try as an expression is illegal, and the return of the last value of a try statement is a noop so equivalent to the old behaviour.
@collinoly
@collinoly 4 ай бұрын
I wish typescript could tell me if something can throw. The amount of things you don’t know can throw is so hard to deal with
@migueljara9399
@migueljara9399 4 ай бұрын
This is actually something I've searched about as I thought the very same thing as you. And luckily, Anders Hejlsberg (C# & TS creator) has talked about it. His opinion was that although beneficial for your code, integrating this with 3rd party libraries would be really bad DX as you would have to handle a bunch of cases that you may not even be interested about from these libraries. Of course his opinion was much deeper than that, but that's the overall opinion I got from him. I don't wanna link anything here as I don't know how youtube treats comments with links (bots are allowed but actual people not, huh?). But you can look it up as "The Trouble with Checked Exceptions A Conversation with Anders Hejlsberg, Part II" it's an article from "Artima" where they interview uncle Anders. It's a good and recommended 5min read :)
@panmateusz
@panmateusz 4 ай бұрын
I wished that once too, and then I tried java which statically analyses exceptions. It's very annoying to deal with. I think its just better to have one catch-all statement to handle all potential runtime exceptions. (But if if it was an optional feature of typescript I would still like it for some use cases)
@webcodr
@webcodr 4 ай бұрын
@@panmateusz It's a little more complicated in Java. Initially Java used so-called checked exceptions and handling was mandatory. Either by try/catch or using the 'throws' keyword after a method signature with all exceptions this method could throw. Well, that decision didn't age very well and runtime exceptions were introduced. They work basically like JS errors. Older parts of the stdlib and some libraries still use checked exceptions, more modern parts and most libraries use runtime exceptions. This is also very annoying. I'm really thankful that JetBrains dropped checked exceptions in Kotlin completly. There's an annotation available instead of the keyword 'throws', but it's not mandatory to use it. But Kotlin allows you to not use exceptions at all. Thanks to sealed classes and some other language features, it's very easy to implement a result object for handling success and error states (Kotlin has a native result class, but IMO it's not that great, so I wrote my own). It's not as convenient as with Rust, but it works fine, makes error handling easier and forces you to handle errors. It's a little verbose at times, sometimes annoying, but in the end, a way better error handling with less potential for bugs. And at least for my taste, nicer than Go's approach will tuples and the omni-present null-checks of err.
@kered13
@kered13 4 ай бұрын
You should just assume that every non-trivial function can throw (this is usually true).
@Goshified
@Goshified 4 ай бұрын
I'm not sure why this wasn't mentioned, but `finally` helps a lot when writing `try/catch` in JS. There are a lot of control flow issues that you can solve there. It allows you to write some code after that will execute even if the failure happens.
@captain.america1123
@captain.america1123 4 ай бұрын
It's a bad idea to have control flow statements inside the `finally` block. It should only be used for cleanup code, ex: Closing files, DBs etc.
@Goshified
@Goshified 4 ай бұрын
I definitely agree that it’s not something that should be used _all_ of the time. In retrospect, my original comment shouldn’t have called out the “control flow” piece specifically. I only meant to draw attention to the third part of “try/catch” that isn’t discussed much which can be used to solve _some_ issues and help with writing cleaner code.
@3ventic
@3ventic 4 ай бұрын
I just pull those kinds of short try-catch variable definitions into their own function and suddenly it's no longer a problem. It can even be a local function within the function that needs to do it.
@darylphuah
@darylphuah 4 ай бұрын
Great to see you learnt why its a good idea to scope the try block.
@3lH4ck3rC0mf0r7
@3lH4ck3rC0mf0r7 4 ай бұрын
I mean, anything that might depend on unreliable (read: may fail/error) code is also, by definition, unreliable. A chain is only a strong as its weakest link. Therefore, it makes more sense to put the lines that may throw, and everything else that depends on it inside the try block, especially since in this simple case it just conditionally doubles the value and returns it with no extra dependencies. This solves the problem of trying to access an out-of-scope variable, and also keeps the code better organized, and easier to read and maintain. Keep in mind, I/O failure is also a thing. Your file may succesfully open, but that doesn't necessarily mean it'll succesfully read, or write. Might as well group all operations involving the same unreliable foreign resource into a single try-catch block. Also, var hoisting is a mistake and should be violently ignored moving forward. It's only kept around for backwards compatibility with old, broken code. Please, just pretend it doesn't exist. The only circumstance one could possibly prefer var hoisting is to use it instead of the finally block, to check-not-undefined and then free resources. But it's ridiculous, no sane person would prefer to declare, but not define a variable at the top of the scope, IMPLICITLY. And if you think you found a legitimate usecase, please just study more. There's a reason why this behavior does not exist in other languages, and if you want to declare, but not define a variable at the top of the scope, you have to do so explicitly. If it wasn't because mistakes were made and old JS must still continue working, let would've replaced var.
@BuyMyBeard
@BuyMyBeard 4 ай бұрын
Another reason to love Rust with match assignment destructuring and Result monad. Dealing with failable code while assigning something is a piece of cake.
@SG_01
@SG_01 4 ай бұрын
With a lot of people doggedly holding on to their various opinions, it's honestly good to see someone change their opinion while working through something. Honestly based.
@paxdriver
@paxdriver 4 ай бұрын
@6:23 Theo finds his own error message interesting 😂 Love these javascript vids. Catharsis all wrapped in a senseless block. You should do one on defining objects with variables for keys. That syntax is so confusing where the key can be dropped or wrapped in brackets, or spread, but only shallowly spread... And there's no built-in optimised deep copy! I have to trust a util or write a case for every symbol, collection, set, array, etc, etc if I plan to reuse it lol
@lukasgerhold7822
@lukasgerhold7822 4 ай бұрын
structuredClone() is a built-in deep-clone function if I understood your problem correctly
@drizzly_dips
@drizzly_dips 4 ай бұрын
@paxdriver lodash solves deep copy (and a bunch of other utilities that should be be built in). big time saver.
@Tyheir
@Tyheir 4 ай бұрын
If err != nil
@theairaccumulator7144
@theairaccumulator7144 4 ай бұрын
worse
@vinialves12362
@vinialves12362 4 ай бұрын
​@@theairaccumulator7144 you are worse, this is better
@steadexe
@steadexe 4 ай бұрын
@@theairaccumulator7144 I don't think it's worse, atleast it doesn't indent the code for no reason. But I agree it might get more chatty if you need to handle several errors.
@paca3107
@paca3107 4 ай бұрын
its annoying but useful
@CottidaeSEA
@CottidaeSEA 4 ай бұрын
@@steadexe You should place as little as possible inside your try-catch. If your entire code is wrapped in a try-catch then that's just a skill issue. The indentation should be pretty much the same as what "if err != nil" causes. In fact, wrapping as little as possible in try-catch is preferable since if you have a lot of your code wrapped in it, you might catch unexpected and unintended errors which could be problematic in many ways. You also want to handle errors as quickly as possible and restore to a normal state, or exit with an expected failure state rather than an unknown one.
@warrenarnoldmusic
@warrenarnoldmusic 4 ай бұрын
A bug: skill issue Js devs: it must be the language, no it is the browser, no it is the device 💀😅
@chriss3404
@chriss3404 4 ай бұрын
it's always the hardware's fault!
@shaunmodipane1
@shaunmodipane1 4 ай бұрын
3:07 I don't get what is wrong with having all your code inside the try block.
@shaunmodipane1
@shaunmodipane1 4 ай бұрын
and what is wrong with if-else to handle errors or "unexpected"/not happy paths conditions
@Pete133
@Pete133 4 ай бұрын
Yeah I don’t see why it’s bad either. If you want to handle errors from the other function call then why not put a separate try/catch in that other function?
@kered13
@kered13 4 ай бұрын
The problem it separates the error handling from the point where the error arises. As the function becomes longer, this problem grows. The solution is typically to factor out the part of the function that can fail into a new function that includes the error handling.
@matthewchampagne9621
@matthewchampagne9621 4 ай бұрын
The problem is that hoisting shouldn't be an option. That makes no sense. Scopes should always be real and have no edge cases but that's JS for you.
@tinytim42
@tinytim42 4 ай бұрын
We have to choose between consistent block scopes or marginally better ergonomics here. I’m happy the authors chose consistency.
@alexandr0id
@alexandr0id 4 ай бұрын
Try catch behaves like this in all Java-like languages. The whole try-catch pattern is rotten and it's not JavaScript's fault.
@dazraf
@dazraf 4 ай бұрын
i'm not functional programming this is a topic as old as time. basically an Either monad that can be passed from one function to the next.
@velitasali
@velitasali 4 ай бұрын
Bruh 10:05, if you know try block is not going to fail then keep things in the try block, wth on about there. Also it is not that try block is a control flow in and of itself but anything is a scope when you put them inside {}. You can create scope with {} without using any keyword, you know that right?
@erikbrendel3217
@erikbrendel3217 4 ай бұрын
Nice! Thanks for openly showing that changing your mind after learning something is a good thing :D
@bagofmanytricks
@bagofmanytricks 3 ай бұрын
In JS you need to think of try-catch as something that protects a whole scope, like the whole function. Happy path should happen in try{} and Failure path should happen in catch{}. If something always needs to happen last it must happen in finally{}
@bloody_albatross
@bloody_albatross 4 ай бұрын
In Python a try block can have an else block, which only runs if there was no exception thrown. With proper scoping that would make even more sense than in Python. So you could do: try { const x = foo(); } catch (e) { // cannot use x } else { bar(x); } finally { // cannot use x } // cannot use x
@pyrouscomments
@pyrouscomments 4 ай бұрын
I kinda see what you mean, but I'd argue this makes even less sense in Python and is in fact one of the reasons that: 1 - variables are not declared; 2 - not every block suite creates a new scope. What I mean is that the confusion on what's defined were in the control flow in general is something to avoid as a design principle, which leads to the above two points. Anyway, I keep trying to give JS a chance, but...
@Lambda_Ovine
@Lambda_Ovine 4 ай бұрын
aaannnd this is why i kinda dislike python... an esoteric block of code that can only run if there was no exception and conceptually merges if and try blocks? shouldn't the code that only runs if an exception wasn't thrown be just the rest of the function? just pre-set your variables outside the scope when it applies people, is not the end of the world
@bloody_albatross
@bloody_albatross 4 ай бұрын
Another solution would be a try expression where the try block can return a value (or return from the function). Then you can declare the variable to be set as const.
@ValerianAndStuff
@ValerianAndStuff 4 ай бұрын
what the fuck
@Мартынов-х3ъ
@Мартынов-х3ъ 4 ай бұрын
@@Lambda_Ovineesoteric block of code is kinda funny ngl. There are else statements for both for and while loops in python though, so having it for try is predictable
@jaye5632
@jaye5632 4 ай бұрын
This makes sense if you take the return out of the catch. Anything which is then hoisted could be an error outside of the try catch. Accessing the variable again would mean that you are now referencing the error object
@DNAMIX1
@DNAMIX1 4 ай бұрын
Just put each and every potentially undefined handle (database connection or rather a grab from some connection pool etc.) inside dedicated and properly scoped semantic codeblock, no?
@SirCorrino
@SirCorrino 4 ай бұрын
I like it the way they do it in Kotlin. Where you can return a value from the try/catch and assign that to the variable you want.
@hammerbot838
@hammerbot838 4 ай бұрын
lol I loved the change of mind when you figure it out. Honestly, you can get away with a lot of things mixing the `try/catch` syntax and the `.catch()` syntax when necessary and it's really ok. What bothers me the most with exceptions is that they are not typed. In java, we declare a function saying what the function can throw so the catch block is also typed. This is not the case with Typescript and I believe it sucks
@atlasxatlas
@atlasxatlas 4 ай бұрын
i love the realization mid vid, and acceptance and opinion change. well done
@rubenchiquin3768
@rubenchiquin3768 4 ай бұрын
There's other languages that handle this in a very unique way, that I think would be doable in typescript. For example Scala's Try Basically it's like a try catch block, but without catch. The catch happens in the type definition. So any exception thrown is saved in the return type. The simplest example is a function to convert a string to number: def parseInt(s: String): Try[Int] = Try(s.toInt) Now the result of the function parseInt is of type Try, which already tells you (much more explicitly than the ghostly typescript errors) that this number that you get returned is really inside this Try wrapper which can fail, which forces you to deal with the error before accessing it, much like Go with their err != nil spam. Just that in Scala, you can decide when to unwrap and deal with the error, instead of doing it right away. With TypeScript having such a strong type system, I'm surprised that it doesn't have anything like this for error handling
@ChrisgammaDE
@ChrisgammaDE 3 ай бұрын
Respect for beeing honest about realizing why it is this way. Also very important as a dev to be honest about beeing wrong
@StereoBucket
@StereoBucket 4 ай бұрын
I've read about hoisting and understood it and then almost completely forgot about it for so many times in the past 8 years that I can't even keep count anymore.
@KAZVorpal
@KAZVorpal 4 ай бұрын
That hair and mustache look like something Weird Al would do as a parody of a failed 70s porn actor.
@HoussamElbadissi
@HoussamElbadissi 4 ай бұрын
I think try scoping makes total sense. The actual solution to the ergonomic issues created by that aren't solved by "removing" the scoping, but one option would be to make "try/catch" an expression (i.e. it returns a value, can be assigned to a variable). Something like this: const num = try { getNumber() } catch (e) { console.log(e); -1 } This is the way Kotlin works, and makes code very nice and readable. However, I'm not sure if this syntax is really fit for JS to begin with (the implicit return), so there's that. Bonus: it's also very TypeScript friendly, as it can automatically make a union type out of the return values for each of try and catch blocks (or `T | undefined` if one of them doesn't return).
@tekbal
@tekbal 4 ай бұрын
Not a dumb thing. The fact that you do not realize that this behavior is by design is what truly sucks.
@MrManafon
@MrManafon 4 ай бұрын
Every day, I miss Elixir where a try statement may have a return value. Solves the issue of graceful fallback
@chadjaax
@chadjaax 4 ай бұрын
JS does that because it create a new scope whenever it encounter { }, you can even do something like main:{ // something somethig } and it will be an entire new space there. of course the facking var will escape it.
@einargs
@einargs 4 ай бұрын
Explicitly defining the variable outside makes it obvious that it needs to be handled to people coming in later. The better answer is the ability to use try as an expression. Theoretically no scope could make sense in a different operator where catch guarantees you leave the function.
@MaxPicAxe
@MaxPicAxe 4 ай бұрын
What we need is post-initializable constants in JS and TypeScript should be able to handle this in the type system to ensure no funky behaviour.
@londek
@londek 4 ай бұрын
I thought it's default mindset that anything in any { } should create a scope
@byebaum
@byebaum 4 ай бұрын
Applying normal scoping to a try block encourages you to put code in the try that doesn't relate to the error condition that the catch is intended to deal with, but which needs to access values computed in the try. I prefer for try blocks to be as small as possible, and only cover the code which the catch deals with, but that then complicates getting data out of the try block because of the scoping rules.
@ProfessorTimbo
@ProfessorTimbo 4 ай бұрын
Your 2-space-width tabs make you my sworn enemy.
@ocks_dev_vlogs
@ocks_dev_vlogs 4 ай бұрын
Having the try/catch statements both be something that is considered their own code blocks is honestly something I agree with. Try only runs code up until an error is thrown, in which case it then runs the catch code, so if you define a variable within a try block but it crashes before it reaches this definition, then using this undefined variable outside the try statement wouldn't be possible. I also like the brackets counting for consistency, where every block created with {} is its own block. It would be really strange if try was the only block with brackets that didnt create a scope, and since it creates scope it prevents the accessing of a variable that doesn't exist.
@CottidaeSEA
@CottidaeSEA 4 ай бұрын
One of the things I have a problem with when it comes to JavaScript is that you often have absolutely no clue which functions may throw. It's crazy.
@marloelefant7500
@marloelefant7500 3 ай бұрын
5:30 is not quite right. If get number() throws an error, num won't exist as well. An exception stops the execution of the try block and jumps straight to the next catch block. Consequently, the assignment to num never happens.
@minikame2272
@minikame2272 4 ай бұрын
I started pulling my hair out thirty seconds into this video but by the end was so fucking happy. Not just that you flipped sides (although as you say the DX does suck) but because it takes a distinct absence of ego to call BS on your own position after spending nearly ten minutes explaining it in public. If only more debates and conversations were had in good faith like this. Alright I've been watching you for like two years ago but because of this particular one, yeah okay, I'm finally clicking the fucking sub button.
@maciejcisowski7015
@maciejcisowski7015 4 ай бұрын
This should not take a toy example and this amount of soul-searching from any dev with a modicum of experience.
@unalive_me
@unalive_me 4 ай бұрын
It should be changed to use the try statement where an error will occur, and have a catch block, that must return, follow that try statement. That way you're forced to handle the error if you need a value set: try logSomething(); try const num = mightError(); catch (e) { console.err(e); return -1; } const double = num * 2; return double;
@lackofsubtlety6688
@lackofsubtlety6688 4 ай бұрын
I am glad you changed your mind, because it makes 100 percent sense.
@AndreGreeff
@AndreGreeff 4 ай бұрын
just for the sake of clarity around the 3:00 mark: obviously, moving `const num` into the `try {}` block while leaving `const double` outside of said block will break, because that's how ES6 and the "block-scoped" `let` and `const` were designed to work. these did not replace `var` as everybody loves to tout. `try`/`catch` was around long before ES6, if you use `var num` (which is not block-scoped) inside the `try { }` block, then `num` is accessible outside of the `try`/`catch`, and you won't get a "ReferenceError: num is not defined"... this is only an issue today because we have different "building blocks" to play with, blocks that the designers of the other, older "blocks" did not foresee. my point is: when you use `var`, then `try`/`catch` makes sense. if you use `let` and/or `const`, then it does not.
@AndreGreeff
@AndreGreeff 4 ай бұрын
but wait... it doesn't "hoist `var` out" of the block, `var` is simply function-scoped, not block-scoped.
@artman1212
@artman1212 4 ай бұрын
The problem is not with the try/catch but with the entire concept of throwing errors.
@AndrewSmithDev
@AndrewSmithDev 4 ай бұрын
Result types are just much better. In JS you can just ignore an error and crash your entire program. You may not ignore it. You may just be oblivious about it but the result is the same. Your program crashes. With a result type, you're forced to handle the error. There's also no type for the caught error because you can throw anything as a JS error. If there was a result type then we could type the error.
@ritsu133
@ritsu133 4 ай бұрын
custom classes that extend Error /w instanceof checks I mean you can write `throw 1` but I feel like it's a developer's problem if they do that. result types are verbose BTW and you don't need to always handle the error really, although I kinda agree
@travistarp7466
@travistarp7466 4 ай бұрын
@@ritsu133 How do you know the possible errors a block can throw.
@theairaccumulator7144
@theairaccumulator7144 4 ай бұрын
Nah they're really much worse. You don't care about 99% of errors that are thrown and just want them to bubble up to a request/global handler so they can be logged and an error response can be sent. Having thousands of if err != nil return nil, err just makes the code less readable and prone to typos and it doesn't solve the problem of having different types being thrown. Typescript at least lets you specify the error you care about in the catch block but in JS you have to do an instanceof check and then throw the ones you don't care about back which is the same thing under the hood just a little more terse. But it's still better than 2 if checks for err != nil and err being the one you care about.
@JackBond1234
@JackBond1234 4 ай бұрын
On the other hand, "every code block is a contained scope" is good in its simplicity. It'd be nice if there were some alternative that doesn't require a closed block though
@byebaum
@byebaum 4 ай бұрын
I think the better solution to using an uninitialized variable is for it to be an error to use a variable whose var statement hasn't been reached, just like it is for a let or const.
@beorntwit711
@beorntwit711 4 ай бұрын
This is an argument i heard a while back, where the guy was pushing 'await' with .catch notation.
@asailijhijr
@asailijhijr 3 ай бұрын
Does the blocking behaviour of the try block also happen in a do{}while()?
@asailijhijr
@asailijhijr 3 ай бұрын
I commented too early. Just like the video says, yes, it does.
@KaiHenningsen
@KaiHenningsen Ай бұрын
There's a reason try{} is a scope for declarations in pretty much every language that has try{}.
@blacky7801
@blacky7801 2 ай бұрын
This is the exact reason why they made var hoist variables. Beginners declaring variables within if blocks and wondering why they cannot access the variable outside the if block.
@Thomasvanlankveld
@Thomasvanlankveld 4 ай бұрын
My workaround is wrapping the try/catch in an iife, so that I can just put the return value of the fallible call in a const and get on with my life
@gabrielcastilho4168
@gabrielcastilho4168 4 ай бұрын
You can fix that by allowing to return from try into a variable. Rust's do that, you can assign any block to a variable
@Bu7MaiD075
@Bu7MaiD075 4 ай бұрын
Imagine having all of your variables not being destroyed after the try block.
@RoyRope
@RoyRope 4 ай бұрын
Hmm for me it actually makes perfect sense, it is expected part of the try clausule is not executed(completely) so variable declarations can not be assumed after the try clausule.
@funkijote
@funkijote 4 ай бұрын
Why not use a Go-style error handling pattern in JS as implemented in the 'attempt-promise' JS package? That is, wrap a function in a sort of try/catch utility function that returns a 2-item array containing either an error or the desired result in positions 0 and 1 respectively, and then use regular if statements to do one thing if err, and another if not err. So, for example, inside of some function we use a wrapper called 'attempt': const [err1, user] = await attempt(User.find(id)); if(err1) { /* ...handle error and return */ } /* ...do some stuff with user */ const [err2, product] = await attempt(Product.find(id)); if(err2) { /* ...handle error and return */ } /* ...do some stuff with user + product */ return { user, product };
@theairaccumulator7144
@theairaccumulator7144 4 ай бұрын
That reduces your performance by a lot because you're spamming heap allocations and GCs just to return a value from a function.
@funkijote
@funkijote 4 ай бұрын
@@theairaccumulator7144 True probably, will devise a test this weekend of if/the scale at which it matters.
@funkijote
@funkijote 4 ай бұрын
​@@theairaccumulator7144 So, haven't tested scaled performance of my hackey solution yet, but it turns out the pattern I described (with a better underlying implementation obviously) has formally been proposed as a JS standard kzbin.info/www/bejne/m5mYg4ybpdeLers
@pooyaestakhry
@pooyaestakhry 4 ай бұрын
Yes, but no. while try scoping can be painful to use in some or many cases, it would be more confusing to have blocks (code between curly braces) act differently when it's try and normally everywhere else
@Bittboy
@Bittboy 4 ай бұрын
Honestly, I believe the way it's setup is correct (given how JS works). If a for-loop has the same behaviors, why should try-catch be an exception? If the first baseman catches a ball thrown by the pitcher before you get there, you're OUT. You don't get to keep going all the way to the umpire/home plate - you're no longer active or assigned any role or position until you get called to bat again. If you're trying to define variables inside a try-catch but use them outside of it, then at least figure out why you're doing that instead of arguing about the implementation no different from other scopes. Obviously what I've said does not apply to other languages that were designed with these things in mind, but since JS already has a definition of a "scope" then it only makes sense to follow the standard, not create an entirely new one to please a few people.
@davorinrusevljan6440
@davorinrusevljan6440 4 ай бұрын
The "only" reason is exactly why it should be the way it is.
@harryhack91
@harryhack91 4 ай бұрын
2:55 Me, as a Java developer: "I don't see the issue here"
@steadexe
@steadexe 4 ай бұрын
I think the only thing we can all agree, is that error handling in javascript (try/catch) is ugly. If only there was a middleground between callback (returning error and data) and promise. Like a sugar to return an array of error and data like golang but for promises.
@DanKaschel
@DanKaschel 4 ай бұрын
Rust handles this so nicely. But in js i would love a try catch that looked like a ternary where the second value is a function with an exception argument. If the first returns a value, the second must also. That way variables still end up getting set.
@simonhartley9158
@simonhartley9158 4 ай бұрын
If there was some keyword other than var for this, once people were familiar, I'm sure it would be fine. For compiled languages, I've also seen the concept of flow scope, where the variable can still be accessed if nothing can potentially cause it to be uninitialized.
@InfinityN
@InfinityN 4 ай бұрын
This video is a whole ass skill issue.
@Blackilykat
@Blackilykat 4 ай бұрын
6:30 "that's the only reason that try/catch could ever reasonably be thought to keep things in its own block" I rarely write js but almost every time I've handled errors I didn't immediately return. IMO try/catch is definitely control flow as it expects part of the code to not be executed some of the time, and when that happens it executes another block.
@Blackilykat
@Blackilykat 4 ай бұрын
i did not finish the video before commenting
@bigmontz
@bigmontz 4 ай бұрын
If you open a random scope like { } without any kind if, else, try, whatever, the const and variables define there can be only be used there. This also happens in C/C++ and other languages. This comes back to memory and other resources allocation. So you are able to free those resources wherever it is not useful. Apart of this, it makes the code more consistent. Why should try block have a different behavior of any other block construction in the language? A block is a block and it should behave the same as it does.
@MrMudbill
@MrMudbill 4 ай бұрын
Try-catch in JS is a mess for many reasons. My favorite pain points are scoping, as mentioned, as well as having to do if instanceof checks for different types of errors, and possibly worst of all not knowing which errors are potentially thrown at any given time. Considering you can do like in C++ and throw literally any value, it makes it very difficult to catch the errors gracefully because `error` will always be `any` type. It's just a lot of boilerplate to deal with.
@NateVolker
@NateVolker 4 ай бұрын
I use this HOC a lot because of how ugly try/catch is: const safe = (fn, valueOnError) => (…args) => { try { return [fn(…args), null]; } catch(e) { return [valueOnError, e]; } }
@anon_y_mousse
@anon_y_mousse 4 ай бұрын
It's good that you came around to the correct way of thinking that this way of it working makes sense *and* that JavaScript sucks. Another example for you, consider a normal block in a language like C: int main ( void ) { int a = foo(); int b = bar(); { int c = a + b; } printf( "%d ", c ); return 0; } // will not work because `c` had scope only within that inner block, but would if the printf() call was made inside that inner block. This is an overly simplistic example, but it demonstrates the point all the same that a variable can leave an inner scope.
@lautarodapin
@lautarodapin 4 ай бұрын
funny thing about python, now with the type hinting you can build an error handling system like rust or go OkType = TypeVar("OkType") ErrType = TypeVar("ErrType", bound=Exception) Result = Ok[OkType] | Err[ErrType] def check_field_exists(something): if something.does_not_exist: return Err(ValueError(f"Field does not exist")) return Ok(something)
@marloelefant7500
@marloelefant7500 3 ай бұрын
According to "Clean Code" by Robert C. Martin, when this poses a problem to you, you are probably doing too much in a single function. They argue that error handling and nothing else should be done in its own function.
@imadetheuniverse4fun
@imadetheuniverse4fun 3 ай бұрын
the thing i don't get is how someone gets annoyed at try scope in the first place? like what are they trying to do that's so insane that a literal inner scope messed them up? every single piece of code you write is scopes upon scopes upon scopes. people don't get how to logic data in and out of scopes or what?
@abraham_o
@abraham_o 4 ай бұрын
Honestly I see no issues here, thank God theo changed his mind. I spend most of my time coding with Python where you'd catch a named exception depending of the event that caused the exception, the only reason why I see this as an issue is where you have deeply nested throw statements when your function is calling another function that calls a function that throws an exception. Thinking about it makes me nervous. 😂
The "Wrong Way" To Use React
39:30
Theo - t3․gg
Рет қаралды 142 М.
Unexpected Lessons I've Learned After 15 Years Of Coding
43:05
Theo - t3․gg
Рет қаралды 101 М.
«Жат бауыр» телехикаясы І 30 - бөлім | Соңғы бөлім
52:59
Qazaqstan TV / Қазақстан Ұлттық Арнасы
Рет қаралды 340 М.
Counter-Strike 2 - Новый кс. Cтарый я
13:10
Marmok
Рет қаралды 2,8 МЛН
Self Reflecting AI Agents BEATS CrewAI and AutoGen in Accuracy!
12:59
Mervin Praison
Рет қаралды 3,6 М.
The Weird Rise Of Anti-Startups
12:57
Enrico Tartarotti
Рет қаралды 415 М.
Someone improved my code by 40,832,277,770%
28:47
Stand-up Maths
Рет қаралды 2,6 МЛН
Why You Should Be Using PostHog
15:51
Nathan Covey
Рет қаралды 1,7 М.
Linus Torvalds: Speaks on Hype and the Future of AI
9:02
SavvyNik
Рет қаралды 268 М.
PirateSoftware is right, this needs to stop
15:14
Theo - t3․gg
Рет қаралды 490 М.
Why Democracy Is Mathematically Impossible
23:34
Veritasium
Рет қаралды 5 МЛН
The Ultimate Tier Programming Tier List | Prime Reacts
26:57
ThePrimeTime
Рет қаралды 508 М.
I'm Ditching Try/Catch for Good!
10:29
Web Dev Simplified
Рет қаралды 189 М.
Making an atomic trampoline
58:01
NileRed
Рет қаралды 10 МЛН
«Жат бауыр» телехикаясы І 30 - бөлім | Соңғы бөлім
52:59
Qazaqstan TV / Қазақстан Ұлттық Арнасы
Рет қаралды 340 М.