And then there is Lisp that handles it however you want it to, including just stopping and waiting for you to complete the implementation or fix it, and then continue from where it stopped.
One of the blockers for throw expressions in JavaScript is operator precedence: `throw a + b` as a statement currently throws a + b, but a similarly looking operator `await a + b` awaits only a, and adds the result to b (yield is similar). It also overlaps with the proposal for do expressions, which'd let one do `do { throw new Error() }` as an expression
I’d love to see Dart’s sound null safety and the operators it brings along with that. Moreover, it’s worth mentioning how awesome and easy dart makes to use null safety.
@@contextfree Not really. Dart's null safety is very generic and uses standard "mainstream" operators for dealing with nullability. In fact it misses some critical ones like `if let` binding from swift or `if (something) |val|` from Zig, which makes it very annoying to work with nullable instance fields (because standard flow analysis cannot infer that, since getters can be non-deterministic and can make standard `if(val != null)` non-decisive). I guess the only rather unique thing dart has is that this nullability is actually sound, and once the type system says a variable is non-null, you can be absolutely sure it is true (unlike kotlin)
I'd love if you could interview Richard Feldman about the language he's working on, Roc. He's a super super interesting dude with really pragmatic insights about functional programming.
Perhaps comparing that with Rust’s monadic result type (.and_then appears to be the monadic application operation, since it carries state between steps if successful and sends an error to the end if and when produced).
I hate Odin now. Returning two values, but only one of them has a real value? It's almost as if you use multiple bools where you could use a single enum.
Hi, here you focused only on one kind of usecase for exceptions: (1) returning alternative values. There are two other usecases: -(2) non deterministic errors, like StackOverflow, MemoryOverflow or (for example in Java) VerifyError (bytecode is messed up during class loading) -(3) situations explicitly marked by the programmer as explicit bugs. While all the solutions shown in your video work well for (1), we really need some kind of non local control flow jump if we ever want to handle (2) and (3). For example to make sure that our nuclear plant enact some failsafe operations instead of just crashing. Of course it is fine to only focus on one aspect, but it would have been nice to mention the existence of the other two
My `readWhetherTitleNonEmpty` was to demo error propagation. Of course, there are means other than either throwing or returning errors up the call chain. What methods do you find most useful for the examples you gave? And for out of memory, Zig is a great example of a language that gives errors for that case (though I think they still are working out the plans for stack overflow).
" What methods do you find most useful for the examples you gave?" For case 1, passing lambda to handle all the cases looks likes the cleanest solution to me, as in "myList.getTop(e->onElement(e), ()->onEmpty())", but funny enough my own language is not able to support that :-) For case 3, Conventional java style unchecked exceptions may work best. However, may be we do not need the implicit typecase that comes with the catch. Maybe using subtyping to classify errors is not optimal. Case 2 is different from case 3 if you want a language giving some kind of control over (non)deterministic behaviour; hopefully that difference can be encoded just in the type system.
A stack overflow will result in a crash 99% of the time before you can ever catch it and even if you do catch it you could have easily nuked your whole stack already depending on which CPU architecture and OS are we talking about. You can have a signal handler that catches the signal given by the OS when you crash and does something accordingly and you can resume the execution of your program afterwards if you want, that can be done in basically every language. Secondly, stack overflows are not "indeterministic", the stack has a given maximum size it can have in a given CPU/OS and if you surpass it you will encounter a stack overflow, simple as. If you are deploying code to a nuclear station you should probably know this and make your code with discipline in such a way this doesn't ever happen and then torture test your code extensively, the best way to handle errors is not to have them. For example, in MISRA C wich I would assume is similar to what people who write critical nuclear central code do, recursion is not allowed at all precisely for this reason. But C++/Java style try catch is never the answer, that only ever makes the control flow of your code orders of magnitude harder to understand and thus makes it more likely to have bugs that compromise security, its literally the worst idea in the history of programming.
@@marcossidoruk8033 " the best way to handle errors is not to have them." I can not disagree more. Look to the 'zip' function in haskell, by making a library design where there should not be error, we create an environment where user errors ended up hidden instead of properly explode the system. (in most use cases for zip we are assuming the two lists to have the same lenght and it is an user error if it is not the case). Errors are CRUCIAL to make libraries
I do want to ask, what's the purpose in using match () and an if guard over simply an if expression? I wouldn't personally use match if I didn't care about the pattern, but maybe it's some style thing I'm not seeing.
Love your content as always, although I would definitely like to see V examples. I feel like the same people who follow Zig, Odin, and Nim development would also like to learn about how V handles these cases too!
Really nice summary! It's a bit disappointing that Odin went with tuples instead of a tagged unions for errors - it's a bit of a mistake in the design of Go imo. :[ OCaml is interesting since you can use polymorphic variants for the errors when using `result`, which reduce the boilerplate of combining error types that you get in Rust.
It's not tuples, it's real multiple return values. And it's really nice to use, since you don't have to define any types and the whole thing is very flexible; edit: Odin has tagged unions as well but they are used in different places; I was skeptical of it myself in the beginning, but I really don't see any benefit either way usage-wise, it's mainly a syntax thing; you can pass them around the same way, you can ignore errors the same way, propagate the same way, etc.
@@kim15742 Eh, I'd say that multiple return values are effectively a limited from of tuple. It just seems very strange to use a "this-and-that" return type for something that should model something that should only ever be used as "this-or-that". There's too many "degrees of freedom" in the return type, and I'd imagine it's pretty error prone (easy to forget to check if there's an error present, easy to return both a success value and an error by accident).
@@bjzaba Idk, these seem like justified fears when you think about the topic but that never happen in practice. And in Odin the multiple return values are actually more powerful than tuples, since you can forward them to the next function that takes n arguments. One thing that Odin intentionally doesn't have is Rust's .unwrap. In Rust that is used everywhere and it's kind of irresponsible
Odin does not have tuples, multiple return values are denotational-semantically distinct from tuples. Odin also allows you to use discriminated unions if you so do prefer, it is that multiple return values is preferred for this case for numerous reasons. But it's a difference in thinking which is where you are disagreeing. Most non-successful error states are not failure states, many partial success states. Using the "this-or-that" forces you into the "success or failure" (binary) approach whilst the "this-and-that" (ternary approach) allows for the ability to handle case of partial success cases which are a lot more common than you'd think. The canonical example would be reading from a generic data stream. What happens if you N bytes but also come across an EOF. Is an EOF a failure state? I highly recommend reading the articles that I have written here: www.gingerbill.org/article/2021/12/15/multiple-return-values-research/ www.gingerbill.org/article/2021/09/06/value-propagation-experiment-part-2/
For the TypeScript example, you could've used Promises which would've acted like Rust's Result() in the sense that you can reject it at any time or resolve it.
@@NicolaLarosa exactly, zig just feels simple and as easy as it can be for low-level language. Explicitness, error-handling, zig's zen. Can't wait for 1.0 release!
@@NicolaLarosa After several years, really? It's honestly not that hard once you understand a few rules. It becomes easier with a few exercise projects.
@@echoptic775 Man, this isn't some mystic kung fu style, this is just another programming language. Working with it full time for 2 months is more than enough for an experienced programmer to utilize it fully.
@@contextfree I wanted to mention a C++ implementation that mimics Result and Option from Rust and offers a similar monadic interface (didn't include any links) but I guess the comment filter didn't like it. It's by TartanLlama in case someone wants to take a look.
Why do people want to code in a way that to doesn't throw exceptions. It literally makes debugging a nightmare, because inevitably you end up just printing that exception into your doc (pointless) or you just end up ignoring some future exception that you didn't anticipate (harmful). WHY DOES ANYONE WANT TO DO THIS? IT LITERALLY MAKES NO SENSE AND DRIVES ME UP THE WALL.
Great content. Many thanks. I have only one wish/proposition. Can you please record your videos with 30fps quality, so when someone like me looks it in FHD on 2x, it doesn't freeze because of internet speed is not fast enough.
I find 60fps a great experience, more creators should switch to it. I don't know how you can absorb information like this at x2 speed but you should consider lowering your video quality setting or try finding better internet provider. This is very specific case, most people should be able to enjoy 60fps glory :)
@@voltflake > you should consider lowering your video quality setting or try finding better internet provider. So, lowering my video quality on video with mostly static content? Sounds like horrible idea, it has nothing to do with "great experience" as for me. If I can't consume some information on 60-70 mbps internet speed, that's not a problem with internet provider. > This is very specific case, most people... How you can tell for "most people"? Did you do some stats? Majority of my colleges watch screencasts/conferences on 1.5/2x speed, my friend often watch youtube on 3x (yes it's possible), why we all should "enjoy 60fps glory" with constant lags?
@@olehdevua I don't want to argue but I just throttled my internet connection to 10Mbps (1.20MB/s) and any 1080p60 video on RUclips, including this, played lag-free even with x2 speed. You probably have WiFi or stability issues. As for 4K60 at x2 speed it played flawlessly with 60mbps (7.15MB/s) connection.
Thanks much to Ornella Friggit-Konaté for hi and bye in French! twitter.com/zerornella
Nowhere else that I’m aware of on youtube you can find hype-free head to head comparison of multiple language like this. Thanks for channel.
This channel is a hidden gem
And then there is Lisp that handles it however you want it to, including just stopping and waiting for you to complete the implementation or fix it, and then continue from where it stopped.
surprised to hear French just at the beginning ^^
Salut
Au revoir
petit coucou au développeur français
One of the blockers for throw expressions in JavaScript is operator precedence: `throw a + b` as a statement currently throws a + b, but a similarly looking operator `await a + b` awaits only a, and adds the result to b (yield is similar). It also overlaps with the proposal for do expressions, which'd let one do `do { throw new Error() }` as an expression
I’d love to see Dart’s sound null safety and the operators it brings along with that. Moreover, it’s worth mentioning how awesome and easy dart makes to use null safety.
It looks fairly similar to Kotlin in this regard, but I haven't looked closely. Are there important differences to be aware of?
@@contextfree Not really. Dart's null safety is very generic and uses standard "mainstream" operators for dealing with nullability. In fact it misses some critical ones like `if let` binding from swift or `if (something) |val|` from Zig, which makes it very annoying to work with nullable instance fields (because standard flow analysis cannot infer that, since getters can be non-deterministic and can make standard `if(val != null)` non-decisive). I guess the only rather unique thing dart has is that this nullability is actually sound, and once the type system says a variable is non-null, you can be absolutely sure it is true (unlike kotlin)
Thanks! I guess Kotlin sacrificed some of that for easier Java interop.
I just wanted to say how glad I am to have stumbled upon this channel. The content is extremely fascinating and the presentation is exquisite! :)
I'd love if you could interview Richard Feldman about the language he's working on, Roc. He's a super super interesting dude with really pragmatic insights about functional programming.
Thanks for the comment! I think it's a likely possibility during the next year or so.
I'd like to see a Haskell version, with monads and suchlike
That was in my first two takes for this video, but I cut it for length. Hopefully coming soon!
Perhaps comparing that with Rust’s monadic result type (.and_then appears to be the monadic application operation, since it carries state between steps if successful and sends an error to the end if and when produced).
I hate Odin now.
Returning two values, but only one of them has a real value? It's almost as if you use multiple bools where you could use a single enum.
Hi, here you focused only on one kind of usecase for exceptions: (1) returning alternative values. There are two other usecases:
-(2) non deterministic errors, like StackOverflow, MemoryOverflow or (for example in Java) VerifyError (bytecode is messed up during class loading)
-(3) situations explicitly marked by the programmer as explicit bugs.
While all the solutions shown in your video work well for (1), we really need some kind of non local control flow jump if we ever want to handle (2) and (3). For example to make sure that our nuclear plant enact some failsafe operations instead of just crashing. Of course it is fine to only focus on one aspect, but it would have been nice to mention the existence of the other two
My `readWhetherTitleNonEmpty` was to demo error propagation. Of course, there are means other than either throwing or returning errors up the call chain. What methods do you find most useful for the examples you gave? And for out of memory, Zig is a great example of a language that gives errors for that case (though I think they still are working out the plans for stack overflow).
" What methods do you find most useful for the examples you gave?"
For case 1, passing lambda to handle all the cases looks likes the cleanest solution to me, as in
"myList.getTop(e->onElement(e), ()->onEmpty())", but funny enough my own language is not able to support that :-)
For case 3, Conventional java style unchecked exceptions may work best. However, may be we do not need the implicit typecase that comes with the catch. Maybe using subtyping to classify errors is not optimal.
Case 2 is different from case 3 if you want a language giving some kind of control over (non)deterministic behaviour; hopefully that difference can be encoded just in the type system.
Thanks much for the reply!
A stack overflow will result in a crash 99% of the time before you can ever catch it and even if you do catch it you could have easily nuked your whole stack already depending on which CPU architecture and OS are we talking about. You can have a signal handler that catches the signal given by the OS when you crash and does something accordingly and you can resume the execution of your program afterwards if you want, that can be done in basically every language.
Secondly, stack overflows are not "indeterministic", the stack has a given maximum size it can have in a given CPU/OS and if you surpass it you will encounter a stack overflow, simple as. If you are deploying code to a nuclear station you should probably know this and make your code with discipline in such a way this doesn't ever happen and then torture test your code extensively, the best way to handle errors is not to have them.
For example, in MISRA C wich I would assume is similar to what people who write critical nuclear central code do, recursion is not allowed at all precisely for this reason.
But C++/Java style try catch is never the answer, that only ever makes the control flow of your code orders of magnitude harder to understand and thus makes it more likely to have bugs that compromise security, its literally the worst idea in the history of programming.
@@marcossidoruk8033 " the best way to handle errors is not to have them." I can not disagree more. Look to the 'zip' function in haskell, by making a library design where there should not be error, we create an environment where user errors ended up hidden instead of properly explode the system. (in most use cases for zip we are assuming the two lists to have the same lenght and it is an user error if it is not the case). Errors are CRUCIAL to make libraries
Such an awesome video!
It would be a good addition if you had also explained error handling in Go.
I do want to ask, what's the purpose in using match () and an if guard over simply an if expression? I wouldn't personally use match if I didn't care about the pattern, but maybe it's some style thing I'm not seeing.
I sometimes find the uniformity clearer. That's all.
Hey, that's my name at 10:40! What an honor.
Love your content as always, although I would definitely like to see V examples. I feel like the same people who follow Zig, Odin, and Nim development would also like to learn about how V handles these cases too!
Yeah. I need to start looking at V sometime. It had a troubled start but they've continued to work on it.
Really nice summary!
It's a bit disappointing that Odin went with tuples instead of a tagged unions for errors - it's a bit of a mistake in the design of Go imo. :[
OCaml is interesting since you can use polymorphic variants for the errors when using `result`, which reduce the boilerplate of combining error types that you get in Rust.
Tagged unions are awesome.
It's not tuples, it's real multiple return values. And it's really nice to use, since you don't have to define any types and the whole thing is very flexible; edit: Odin has tagged unions as well but they are used in different places; I was skeptical of it myself in the beginning, but I really don't see any benefit either way usage-wise, it's mainly a syntax thing; you can pass them around the same way, you can ignore errors the same way, propagate the same way, etc.
@@kim15742 Eh, I'd say that multiple return values are effectively a limited from of tuple. It just seems very strange to use a "this-and-that" return type for something that should model something that should only ever be used as "this-or-that". There's too many "degrees of freedom" in the return type, and I'd imagine it's pretty error prone (easy to forget to check if there's an error present, easy to return both a success value and an error by accident).
@@bjzaba Idk, these seem like justified fears when you think about the topic but that never happen in practice. And in Odin the multiple return values are actually more powerful than tuples, since you can forward them to the next function that takes n arguments. One thing that Odin intentionally doesn't have is Rust's .unwrap. In Rust that is used everywhere and it's kind of irresponsible
Odin does not have tuples, multiple return values are denotational-semantically distinct from tuples. Odin also allows you to use discriminated unions if you so do prefer, it is that multiple return values is preferred for this case for numerous reasons. But it's a difference in thinking which is where you are disagreeing.
Most non-successful error states are not failure states, many partial success states. Using the "this-or-that" forces you into the "success or failure" (binary) approach whilst the "this-and-that" (ternary approach) allows for the ability to handle case of partial success cases which are a lot more common than you'd think. The canonical example would be reading from a generic data stream. What happens if you N bytes but also come across an EOF. Is an EOF a failure state?
I highly recommend reading the articles that I have written here:
www.gingerbill.org/article/2021/12/15/multiple-return-values-research/
www.gingerbill.org/article/2021/09/06/value-propagation-experiment-part-2/
Why is your VS Code never updated. I nervously stare at that 1 for half the video 😅
I have it on system updates for PopOS, and it's usually a bit behind. Not far behind, though.
For the TypeScript example, you could've used Promises which would've acted like Rust's Result() in the sense that you can reject it at any time or resolve it.
definitely fun
Rust is just so good.
And so complex. After several years of trying, I gave up. Zig, here I come.
@@NicolaLarosa exactly, zig just feels simple and as easy as it can be for low-level language. Explicitness, error-handling, zig's zen. Can't wait for 1.0 release!
@@NicolaLarosa After several years, really? It's honestly not that hard once you understand a few rules. It becomes easier with a few exercise projects.
@@timerertimif you think you know rust, you really don't. Rust is easy to learn the basics, but very hard to master
@@echoptic775 Man, this isn't some mystic kung fu style, this is just another programming language. Working with it full time for 2 months is more than enough for an experienced programmer to utilize it fully.
Idk why but my comments keep getting deleted...
Still enjoyed the video very much! :)
It's crazy sometimes, but this one got through. Thanks for stopping by!
@@contextfree I wanted to mention a C++ implementation that mimics Result and Option from Rust and offers a similar monadic interface (didn't include any links) but I guess the comment filter didn't like it. It's by TartanLlama in case someone wants to take a look.
Thanks much!
Not sure if this helps, but RUclips will delete your comment if you edit it too many times (about more than 2 times), at least for me....
@@oof-software ruclips.net/video/GC4cp4U2f2E/видео.html
salut !
Why do people want to code in a way that to doesn't throw exceptions. It literally makes debugging a nightmare, because inevitably you end up just printing that exception into your doc (pointless) or you just end up ignoring some future exception that you didn't anticipate (harmful).
WHY DOES ANYONE WANT TO DO THIS? IT LITERALLY MAKES NO SENSE AND DRIVES ME UP THE WALL.
No C++ version? Boo!
Great content. Many thanks.
I have only one wish/proposition. Can you please record your videos with 30fps quality, so when someone like me looks it in FHD on 2x, it doesn't freeze because of internet speed is not fast enough.
So 60fps is the problem? I'll try to remember to try out 30fps to see if I still like it.
I find 60fps a great experience, more creators should switch to it. I don't know how you can absorb information like this at x2 speed but you should consider lowering your video quality setting or try finding better internet provider. This is very specific case, most people should be able to enjoy 60fps glory :)
@@voltflake Thanks much for the additional feedback. I'll keep this in mind as well.
@@voltflake
> you should consider lowering your video quality setting or try finding better internet provider.
So, lowering my video quality on video with mostly static content? Sounds like horrible idea, it has nothing to do with "great experience" as for me.
If I can't consume some information on 60-70 mbps internet speed, that's not a problem with internet provider.
> This is very specific case, most people...
How you can tell for "most people"? Did you do some stats?
Majority of my colleges watch screencasts/conferences on 1.5/2x speed, my friend often watch youtube on 3x (yes it's possible), why we all should "enjoy 60fps glory" with constant lags?
@@olehdevua I don't want to argue but I just throttled my internet connection to 10Mbps (1.20MB/s) and any 1080p60 video on RUclips, including this, played lag-free even with x2 speed. You probably have WiFi or stability issues. As for 4K60 at x2 speed it played flawlessly with 60mbps (7.15MB/s) connection.