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)
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
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!
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.
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 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.
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).
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/
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.
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.
Using a type system to return undefined? Returning undefined properties inside a non-typed object? Returning something that is not Something, Error or a typed object? Seems both confused and redundant at once...
@@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 RU-vid, 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.