Aliases are helpful in these situations using Users = ;
@bigice71844 ай бұрын
Lol I think people are just going to put that into a new interface to short method signatures back to normal levels.
@_iPilot4 ай бұрын
Empty enumerable is enough instead of Option. Do not return null instead of empty collection. Nick also mentioned that few times.
@cj82-h1y4 ай бұрын
Why return an Option? If there are no results, you can just return an empty IEnumerable, and the calling code will handle accordingly by default.
@WDGKuurama4 ай бұрын
@@cj82-h1yYou get a point, A Result monad would give more info (about errors). As an IEnumerable can also be considered as a multi value modad. There is no point to elevate it further.
@michaeldileo19544 ай бұрын
One tip with LanguageExt options, you can switch on the Case property: Option.Case switch { User u => …, null/_ => … }
@Sayuri9984 ай бұрын
All I can say is, I love when features become part of the C# standard rather than a Nuget package. Better visibility, better documentation, guaranteed bug fixes and security fixes. So much good stuff. And I do so agree 100% with everything you said in this video.
@nommet4 ай бұрын
Guaranteed bug fixes 😆
@GeorgeGeorge-u5k4 ай бұрын
I tottally disagree. We are bloating .NET with pointless features. Bigger dlls, slower performance etc.
@SixOThree4 ай бұрын
@@GeorgeGeorge-u5k Thankfully you don't need to compile in features you don't use.
@gavinrolls10543 ай бұрын
@@GeorgeGeorge-u5ki don't agree that it results in slower performance
@patrickkurmann4 ай бұрын
I've widely used the C# Functional Extension by Vladimir Khorikov for years, which implemented just that. I am glad it now becoms part of C#.
@alexlo56554 ай бұрын
Me too. This is the great library.
@franciscorusso80624 ай бұрын
Me too. Validimir is a rockstar!
@lldadb664Ай бұрын
Thanks for the pointer to this library! Do you think you will continue to use it even with the language updates?
@patrickkurmannАй бұрын
@@lldadb664 yes in complex projects because Khorikov's lib enables easy railway programming. Simple projects: New C# types will do.
@Masterrunescapeer4 ай бұрын
5:15 "Exceptions are incredibly, painfully slow" -> Jon Skeet, "If you ever get to the point where exceptions are significantly hurting your performance, you have problems in terms of your use of exceptions beyond just the performance." Would argue those cases should often just be TryGet or something along those lines if normal logic of possible that does not exist.
@dennisr9994 ай бұрын
Yes, and then Nick also says "using exceptions like this for flow control is bad practice" ;) I also like TryGet, but it only returns Boolean and not the "reason" for the failure.
@GeorgeGeorge-u5k4 ай бұрын
Result pattern is yet another pointless pattern offering nothing. It is becoming like the american quote about opinions. "... everyone has an pattern". Im tired hear people "exceptions extremly slow bla bla". If youre getting nonstop exceptions then your code has much much bigger problems.
@tarquin1612344 ай бұрын
My understanding of programming is that exceptions are for exceptional events, which does not include validation errors, such as a routing id not being found in a database. This is one of the reasons I always advocate doing more in controller actions rather than pointlessly cutting and pasting everything into a service method, because in the action we have direct access to the http response methods, without needing to awkwardly communicate all those scenarios back from service method.
@projectuber4 ай бұрын
@@tarquin161234 We just have our repos throw EntityNotFoundException and use middle ware to translate it to a 404. Might not be crazy quick but meets our needs and avoids a bunch of try catch every where. Convention dictates if it will through Get throws Find will not List will not The other option I could do is AOP but I really dont want to explain IL weaving to juniors.
@leerothman27154 ай бұрын
@@GeorgeGeorge-u5kBeing slow isn’t the main problem. People use it to control execution flow which not what exceptions should be used for. Exceptions should used for…well exceptions not expected behaviour. They are just goto statements with glitter.
@Crozz224 ай бұрын
I'm so happy you emphasize so much the importance of exhaustiveness and forcing yourself to handle all cases.
@joga_bonito_aro4 ай бұрын
Returning result objects was one of the best things I ever did to my codebase.
@BamYazi3 ай бұрын
Exactly the same experience here, been a game changer - started using LanguageExt.Core which also has other Functional style programming stuff - but having to explicitly handle all the result states just made everything in the codebase much cleaner
@mistrzmatik4 ай бұрын
Me: Nick, can I use Rust? Nick: We have Rust in C# Rust in C#:
@ochronus4 ай бұрын
10/10 meme usage :D
@jongeduard4 ай бұрын
Not a full coincidence. F# and Rust both share a strong OCaml language origin too. And with F# being in the dotnet world, lots of things gradually entered the C# area too.
@GameDevNerd4 ай бұрын
// Rust: declares integer called "n" ×&÷>%>×&÷>÷[$*&$
@true_xander4 ай бұрын
@@GameDevNerdlooks very c++ to me
@ranggatohjaya54714 ай бұрын
let age: i32 = 0; 😊@@GameDevNerd
@alexclark67774 ай бұрын
'bout time C# grew a pair of monads
@asdfxyz_randomname21334 ай бұрын
never realized that monads sounds like gonads...
@aurinator4 ай бұрын
Meh, Rust really kicked C# in its Monads IMO... C#/.Net paved the way with async/await, .Net's TPL with asynchronous Tasks, but then Rust comes along and just grabs its developers by those Monads.
@mbpoblet4 ай бұрын
C# has had monads for a long time... LINQ's built out of them.
@AdrianoKretschmer4 ай бұрын
lol, I see what you did there...
@deeplerg79134 ай бұрын
Nick is gonna milk this proposal for 10 more videos
@nickchapsas4 ай бұрын
You have no idea
@peculiar-coding-endeavours4 ай бұрын
As he should
@StephenMoreira4 ай бұрын
As he should.
@sohn77674 ай бұрын
As he should
@Ruisrd4 ай бұрын
As he should.
@chrismantonuk4 ай бұрын
I add a Result with Succeeded, Error, Result properties to almost every project I work on, for this very reason. It works well but doesn’t enforce error path handling, so this is a great feature, very welcome. Will save lots of boilerplate.
@Kotz_en4 ай бұрын
Result type is great, but I don't really see the how Option would be better than Nullable in modern C# projects, where NRT is enabled (and especially if you have warnings as errors). It's essentially solving the same problem. In projects without NRT however, I do see the benefit.
@Turko777772 ай бұрын
With Nullable, the value either exists or does not exist. With Option I have the same, but I can also know the reason for not having it
@joshman10194 ай бұрын
I do a lot of automation work, and I grew to love this feature in F#. It is definitely nice knowing you have handled every possible scenario in some way that will never fail.
@WillEhrendreich4 ай бұрын
Love the Fsharp representation, lets go! lets let em know there's more than 12 of us, and that 12 fsharp devs get done what 100 csharp ones can in less time with less bugs.
@joshman10194 ай бұрын
@@WillEhrendreich It's a fantastic language! I pair it with C# to get a lot of stuff done, and I couldn't be happier.
@VitalMiguel4 ай бұрын
I introduced functional programming in a big company and I must say I really enjoyed working with options result, pattern matching, unions etc. But it takes some time to learn and to read some chaining code when you have a lot of I/O calls. New developers feedback was always this, they enjoy it but they find it hard to understand this new way of thinking. We only had a single bug in production in 3 years that didn't even affect users. It was on cache serialization of a model. Option, Result and enforcing developers to only access the value through pattern matching is the way for no bugs, because 99% of it is when someone forgot to handle a exceptional path on code. We want to achieve that "if it compiles it works" and this helps. I'm also very happy with the introduction of this and see the feedback of devs and next moves.
@2SHARP4UIQ1504 ай бұрын
I agree. At my company, we fired all the QA teams and replaced them with pattern matching, with no more bugs.
@JollyGiant194 ай бұрын
@@2SHARP4UIQ150QA and this are both arrows in the quiver of excellence. Why would you fire them??? That’s insane
@LC123454 ай бұрын
Slowing people down and preventing them from pushing code is a way to reduce bugs too
@2SHARP4UIQ1504 ай бұрын
@@LC12345 That's a good one, and I will add that another way to eliminate bugs is to fully embrace functional programming and eliminate object-oriented programming. 😉😂
@tauiin3 ай бұрын
@@2SHARP4UIQ150 the best way to not introduce bugs is simply to not code anything at all, just fire all your programmers and I guarantee you wont run into any new bugs ever again.
@weicco4 ай бұрын
I've written my own Result, Result and Option classes with Monad support. They work like charm. Plus they do away all null ref exceptions since you cannot write "null" anywhere 😂 Next I'm planning to write like virtual machine upon NET virtual (a bit hard to explain) so I can alter the values like in Unity game engine plus with diagnostic support. After that I'm going to write my own programming language, compiler and virtual machine 😂 Edit. Ah, yes. I'm planning to write library so that you can use Monads in Controllers out of the box.
@fusedqyou2 ай бұрын
Ah yes, reinventing the wheel.
@nooftube25414 ай бұрын
“exceptions are slow” meanwhile in production: million exceptions - 1 second one sql request to big table that returns nothing - 1 second yeah… exceptions are problem
@tarquin1612344 ай бұрын
They're probably a consideration in low latency performance critical code, which APIs are often not. Regardless of performance, exceptions are not for normal operating conditions such as validation; they are for halting the flow because of something unexpected .
@TehGM4 ай бұрын
Exceptions have one benefit: if you use standardized exceptions, you just create a middleware for handling them and suddenly your controllers become really slim, as they should be. The result type, while it's nice we're getting it, will quickly lead to massive bloat in controllers, cause each endpoint suddenly needs to check the result type. Another benefit of exceptions is that unless explicitly handled, it'll terminate the execution of the body at the point of exception - which ensures that application/data doesn't end up in an invalid state. Results pattern shifts that responsibility to the caller, which - depending on the implementation of course - can in theory be error prone. Idk what's the hatred for exceptions. Both result type and exceptions have pros and cons, and both are fine - definitely pick whichever fits your codebase better. I personally am team Exceptions here - the biggest downside is performance, sure - but until benchmarks prove that THIS is the bottleneck IN PRACTICE, then raging at exceptions is just premature optimization.
@Tsunami144 ай бұрын
Exceptions certainly have their place as well I hear ya. But speaking for myself, I follow the motto of "exceptions should only be used for exceptional behavior", and it's always felt a bit icky whenever I've seen/used exceptions as a way to branch the program's core flow. So Option feels like a more natural way to codify that the program should respond differently based on if the object exists. Hope that makes sense.
@ekhm4 ай бұрын
@@Tsunami14 How do you define exceptional situation? Trying to update not existing object isn't exceptional situation? It's not a "normal" path.
@nothingisreal63454 ай бұрын
On the other hand that "magic" implicit error handling somewhere else in the code reduces readability.
@BlTemplar4 ай бұрын
Nobody says that Result is easier than Exceptions. Result is a better way to encode errors than Exceptions but it requires some effort! The code looks nicer with exceptions but it's harder to reason about. You see only the happy path and have absolutely no idea what errors can happen and how they can be handled because the handling happens behind the scenes in some implicit weird way. If you introduce a new error in Result, your code will stop compiling because you don't handle the new error. Most of the time it's what you want. With exceptions no matter how many new exceptions you add to the code base, the compiler won't be able to help you with anything. With Result you can map errors to the response directly in the endpoint logic. C# Minimal Apis have very nice TypedResults feature to help you with that. With TypedResults every possible case and the response body ends up in the return type of your endpoint logic. And since it's a type, a lot of things can be infered from it like Swagger schema and other things.
@bh-schmidt4 ай бұрын
I'm not sure if I'm team exception, I prefer using a Result type for doing my logic, but I confess that if I'm to use this Result where I have to instance an exception and then put inside an object and returning I will definitely go with the throw method. For me it makes no sense to mix the 2 things, you should use exception or result, not both. Unless you are in a specific scenario of course.
@Hawkeyes19834 ай бұрын
This is perfect timing on this video for me! I am scheduled to give a Tech Talk on this topic next Thursday and had already watched your previous video from a year ago covering the Result Type. Needless to say I'm excited about this feature and have been enjoying using a home rolled version based on your example from the first video. Thanks Nick and keep up the great work!
@Sunesen4 ай бұрын
At this point, C# is pretty much turning more and more into F#. :P
@sleeper-cassie4 ай бұрын
The programming language equivalent of carcinisation is that languages keep evolving towards LISP.
@JollyGiant194 ай бұрын
@@sleeper-cassieLISP’s sin was always the those parentheses
@WillEhrendreich4 ай бұрын
as it should.
@bbqchickenrobot34 ай бұрын
Thats a good thing - loved F#. Minus the missing "protected" level access
@Raminiya4 ай бұрын
I think this is a very useful addition. It's also very useful to standardize other methods of error returns such as methods that return -1 in case of error for positive integer results or methods that return and array or list and reserve one field for an error. I hope it will also support the case when there is a result and a warning at the same time.
@LaszloLueck4 ай бұрын
Instead of Result you can use Either Type with Right and Left. Handling is same as Result with .Match and so on, but is in my opinion more the correct type for returning a result or the exception.
@user-tk2jy8xr8b4 ай бұрын
Result type has a built-in "success or error" semantics unlike Either which is just a sum without any additional meaning
@NickSteffen2 ай бұрын
I think the most exciting part about this would be having analyzer support for ensuring all outcomes of a result or option type are handled when returned and seeing some of the older BCL library functions start returning result objects so that if you do use these objects you can link in and return them all the way up the chain. Something even cooler would be having the code analyzer tell you when a result type for an encompassing function doesn't include an error from one of it's sub types.
@bbqchickenrobot34 ай бұрын
So excited foe the Result and Option - Now if we can get immutable variables by default!
@evancombs51594 ай бұрын
Immutable by default will never happen, too fundamental of a change for it to happen. You'll need a new language.
@jongeduard4 ай бұрын
@@evancombs5159 I have long been thinking about this subject, and my conclusion is that it's related to something much larger. Important difference with a language like Rust is that C# manages certain characteristics of on the level of types instead of individual (local) variables and instances. Examples of such things are are indeed immutability (think about records and readonly structs), but also the distinguishment between value type or a reference type. In Rust it's a lot more obvious to manage all those things on for individual variables and values. You customize mutability, references and ownership all locally based on usage. Remember that C# is a GC managed language while Rust is a low level language like C and C++, and therefore has a stronger orientation on performance, while C# tends to keep more things on simpler to use side.
@evancombs51594 ай бұрын
@@jongeduard I don't understand what you are trying to say? I've never used Rust so I'm not sure how these things are handled over there.
@jongeduard4 ай бұрын
@@evancombs5159 Ok, no problem. It's just my thoughts on how programming languages evolve differently with different focus. Just intended in addition to what you said, that you would need a different language. I do agree with that.
@vcrobe3 ай бұрын
Try the F# language. It has these features and many others that cannot be added to C# (like immutability by default)
@tridy78934 ай бұрын
This may help exceptions have their places of dealing with something that is u n e x p e c t e d, together with eliminating the need for returning nulls/nullable types. IMO, Result looks like a nice temporary fix while we wait for this feature. More elegant and as you said it is nice that it explicitly forces one to handle both outcomes.
@BlTemplar4 ай бұрын
Compare http calls with db calls. If the db doesn't work, it's usually a catastrophic failure. For example, master goes down and replica for some reason doesn't become available. It's extremely rare situtation which shoudn't happen. But if it does happen one day, Result won't help me here because my whole application will stop working. That's why I don't try catch my db calls and don't wrap them in Result. But I do so with http calls because they are unreliable and fail often. I can gracefully handle failures with Result pattern. I can explicitly fail fast in my logic on bad requests or continue if I get success.
@tridy78934 ай бұрын
That depends on the use cases and on the business side, how they allow you to handle a catastrophic failure. Some are ok with retrying later, others need compensation. Then this is a question of timing, in some scenarios, it is not ok to wait for 5 minutes, while others are ok with 30 minutes. For how long code should wait and retry is not up to developers to decide. Another example would be when failed requests stay in a queue and get processed as soon as the DB is back. Anyway, I think it is still a good idea to try-catch, log, and then rethrow.
@Artokieffer4 ай бұрын
It's nice to finally see that Microsoft wants to add Discriminated Unions officially in C#. I found them very neat last year when trying them in Rust for the first time, and I have been very tempted to use them with third-party libraries before, but I never took the plunge. Now that I know it will (hopefully) come in a future C# release, I can't wait to use them. In any case, I think it's a step in the right direction because it will force developers to think ahead in order to handle all possibilities that their program could encounter.
@peculiar-coding-endeavours4 ай бұрын
I'd recommend taking the plunge anyway, there are some good ones out there, or you can roll your own. I've used it in production for years now.
@Sameer.Trivedi4 ай бұрын
At this point you C# has enough things to recreate the entire Earth from scratch.
@DaremKurosaki4 ай бұрын
C# is basically that LotR meme of Bilbo going "After all, why not? Why shouldn't I keep it?" to any useful feature in other languages.
@zwatotem4 ай бұрын
It had from C# 2, but now there's 5 ways to do it!
@benqbenq4 ай бұрын
13:35 Why do you skip the next question about monadic behaviour? There's no sense in using these types without monadic binding support, because you would need to match every result you get, and it gets worse especially with nested ones.
@ekhm4 ай бұрын
As always when talking about this pattern, only simple examples with 1 lvl nesting. What about nesting methods in methods in methods? If there's a problem on 3rd lvl, how do you transmit result through all levels? Using a lot of bloating code I suppose?
@peculiar-coding-endeavours4 ай бұрын
For now yes, but that's up to the language designers to fix. In Rust, you can propagate these very simply without always having to check them, and there are libraries to make things very ergonomic. No doubt that people will start doing the same for c#. But I argue that, even if you do need to add some boiler plate, the added explicitness and clarity is worth it.
@BlTemplar4 ай бұрын
Result and Option are monads. Monads must have map and bind methods. But using these methods directly when combining multiple monads sometimes isn't very nice because of the nesting they introduce. That's why FP languages usually have some kind of syntax sugar for these methods. In Scala it's called for comprehension and I believe in Haskell it's called do notation (not really familiar with it). C# already has this syntax too and it's LINQ. Select is map and SelectMany is bind. LINQ can be used to combine multiple monads together and even asynchnous versions of them like Task. You just have to write generic Select and SelectMany methods so that LINQ can use them.
@damianradinoiu43144 ай бұрын
Not really.. this should be addressed by a proper Bind() method. The purpose of the Monad is to act like a "shell" so it should be pretty easy to change the "shell" because the Invariant (T) remains the same, so it would be just one function call away. I had the exact same problem you say in the past and I solved it like that. Furthermore you can transform it in an extension method and it will simply become something like result.Bind() or something like this
@chris200777774 ай бұрын
You mean the developer needs to decide how each function should return a particular result? How horrible!
@evancombs51594 ай бұрын
Try not to nest your methods so much, it results in confusing to follow code. Instead try to create orchestration methods that defines each step in the process, and aggregates the results to produce a new result.
@benmuse1404 ай бұрын
Very much looking forward to this being part of the runtime
@gileee4 ай бұрын
The main issue I have with using Result right now is that I still having to handle exceptions when calling external code (like when I'm calling into ef core to SaveChanges for example) because they throw exceptions on error. If a native Result type is added I hope we'll get versions that return an error result on error which I'll then be able to just return back from my service functions as is. When Java got Optional, in JPA they added, for example "find" functions, which return an Optional as opposed to "get" functions that throw NotFound. Current I have extension methods that wrap a catch over external code calls and return Result.Error(ex). You can handle different exceptions here and return more descriptive Result errors so you don't pollute your code with random exception classes from other peoples code, but it's still a hassle not to be able to propagate directly and handle in one place.
@aremes4 ай бұрын
I'm in the middle of "that big rewrite" of a pretty big monolith at the moment. Basically, the legacy code had so many issues in terms of maintainability, testability, etc. so we decided to rewrite it. It's on track for release to customers later this year. We've basically written our own Result and used it all over the .NET Library Code, the HTTP APIs, etc. We're talking _several_ tens of thousands LoCs.. Great timing for that to come out. Not. Whats frustrating is that our implementation is so damn close to that proposal that it wouldnt be that big of a deal to refactor it to use the built in types. But we'd be forcing our .NET library users (Enterprise developers mostly) to then refactor their business layer too. I wonder what other developers that have been using existing Result packages or in-house implementations in their code base are planning on doing now.
@liquidpebbles4 ай бұрын
I'm looking forward to it. I'm always fighting with myself, should I return a null here or should I just throw an exception? The constant decision making really saps the productivity out of me. So, if I understand correctly, I'll sort of be forced to handle my cases in a standardized way and won't have to keep making decisions between throwing exceptions or returning nulls.
@ravikumarmistry4 ай бұрын
C# is slowly getting all the features that a functional code need in language itself
@obiwanjacobi2 ай бұрын
I think when you introduce a Result type you should also introduce language features to promote (error) results up the call chain. Otherwise it'll get nasty. I have programmed COM in C++ where you had to check the HRESULT after every call. It can get very complex very quickly - especially when dealing with cleaning up resources. So yeah, it looks all nice and simple in the demo's but try to do a real life program and you'll see it's not that easy. Exceptions are great if you use them for the cases where the caller should not need to handle them. Only a couple of cases where you should really handle exceptions (logging is not handling)...
@ProbablePrime4 ай бұрын
It seems that the Language-Ext match function and even the switch style that the language would support, could end up re-producing a similar problem to callback hell. Where everything just continually nests, indenting etc. Think of a multi-step operation where multiple things can go wrong based on prior Result/Option objects. Are there features or patterns that can be applied to mitigate that? I think Language-Ext does this with additional functions, that sort of push you down a Functional approach.
@JollyGiant194 ай бұрын
Result and Option objects are built for functional use so to use them without callback hell does necessitate a functional approach
@user-tk2jy8xr8b4 ай бұрын
LINQ syntax to the rescue
@ProbablePrime4 ай бұрын
@@JollyGiant19 That is fair, I just wondered if there was an approach that didn't use it.
@JeffKwak4 ай бұрын
Wouldn't `Result` be `Result` instead of `Result`??
@WillEhrendreich4 ай бұрын
You'd think that if you're comparing it to fsharp's one. however, the csharp one seems to be assuming you're using exceptions as errors, so it's implicit. this is ... both frustrating and understandable. I can see wanting the streamlined approach of having exceptions be the way it's handled, but custom error types are very nice in fsharp, because you get the oportunity to use a single Error DU.. *shrug*
@CryShana4 ай бұрын
Using exceptions in common flows / hot paths for common stuff is incredibly flawed. Not many people realize just how slow they are and their huge negative performance impact when they are being spammed, which is very easily done by a bad actor spamming invalid data at an endpoint. Exceptions are just that, exceptions. They should be used for things that really should NOT happen and you don't expect to happen. So I'm really glad for these new types that will introduce MUCH BETTER error handling - it's the one thing I always loved using in Rust and I'm glad they work similarily as well
@deeplerg79134 ай бұрын
People have had the "exceptions vs results" debate for years. One of the main problems of result types that I see people mention is that they require a ton of additional code. The people developing C# have to write a good implementation that solves this. And that is beside everything else. It's like the "ORM vs No ORM" debate: for every argument, the other side has two counter-arguments, and vice versa.
@CryShana4 ай бұрын
@@deeplerg7913 No, "ORM vs No ORM" debate is orders of magnitude different. With No-ORM you are not just forced to write a TON more code, it's also more error prone and you are (usually) tying yourself to a single database. But with "Results" the only extra code is a SWITCH statement that just replaces TRY/CATCH - it's LESS error prone, not more because it forces the user to handle every possible scenario. But most importantly, this is not an EITHER/OR situation like "ORM or NoORM" --- Exceptions and Results are meant to be used together. Results for common errors, exceptions for... well, exceptions.
@sohn77674 ай бұрын
@@deeplerg7913the real problem with that debate is that sides are thinking too pure. Pragmatically, you just use what is more appropriate. Hot loop where you can expect 1000 traverses of the unhappy paths? Result type. You are in a thread and you suddenly lose the connection which only happens due to rare unforeseen events like an outage? Exceptions are the only reasonable choice here.
@CryShana4 ай бұрын
@@deeplerg7913 This is not a good comparison. Unlike "ORM vs No ORM" - Results and Exceptions are meant to be used together, Results for common errors, Exceptions for exceptions. Results don't add as much extra code as "No ORM" does - instead they just replace (or extend) the existing TRY/CATCH with a SWITCH or similar. With "No ORM" the development is more error prone because you can easily make mistakes writing everything - with Results you are LESS error prone because you are forced to handle all results. With "No ORM" there is also other downsides like possibly tying yourself to a certain database. But I digress. Results are meant to complement Exceptions, is my point.
@CryShana4 ай бұрын
@@sohn7767 @deeplerg7913 Unlike "ORM vs No ORM" - Results and Exceptions are meant to be used together, Results for common errors, Exceptions for exceptions. And they don't require that much additional code either - as long as you're not too extreme with it, they realistically just replace TRY/CATCH
@SebGruch4 ай бұрын
Good to see, that things that I'd introduced like 10 years ago, now go into language ;-)
@King21-t7u4 ай бұрын
Hey Nick thanks for this great one, actually I faced an issue with a null check, will implement this new way of handling these 2 cases, I think the option and result are somewhat similar to how we handle the multiple call-back promises in JS by then and catch I might be completely wrong here.
@carambanoescacharrado94462 ай бұрын
Amazing I hope they add it soon. 🎉
@scottwalker46194 ай бұрын
I never really understood the “exceptions are bad for controlling flow” argument. If something doesn’t make sense then it is an exception to the logic, when thrown it can be caught and handled explicitly or allowed to bubble up and return in some manner to the user. Returning options of good and bad results just makes me have to handle it directly when in reality if I can’t find a user I want a NotFojndException to bubble up to the user. I don’t want to have to manually return it through the chain
@juliendebache83304 ай бұрын
The most important part of this is that the option is enumerable, meaning you can use linq on them. So select, firstordefault, etc... This is where the magic happens.
@nothingisreal63454 ай бұрын
Hmm. But: the existing code using exceptions will not profit from this. Why not fix the performance issues of exceptions as well? Also: IMHO readability does decrease. The catch block has a clear well know purpose. In the new Map/Match it is not visible that the second lambda is error handling. You can and should add the parameter name to make it clear which part does what. Also the second part can become "ugly" is case you want to to distinguish for certain error types which is perfectly well defined with exceptions. And: now we again have multiple ways to achieve the same objective, which doubles the learning effort for beginners. Finally: what will happen if one of the underlying APIs throws an exception, e.g. the db.SaveChanges()?. Will that be converted into a Result as well automatically? I guess not. You either have to do it in the routine (not shown in the example!) or you will still have to create a catch block.
@mrwensveen4 ай бұрын
While you can do Console.WriteLine inside the Match method, I'd return a string (or Option if you want to stay in monad-land) and move the side-effect to the side (a bit): var msg = user.Match(u => $"The name is {u.Name}", "The user did not exist"); Console.WriteLine(msg); It's pretty close to what I'd normally write with nullable: var msg = user is User ? "The name.." : "Y U no exist!?"; Console.etc.
@pavelmaskevich7611Ай бұрын
Isn't this exactly why the try/catch pattern emerged in the first place? Back in the day, functions would return codes, and if the code was 0, it indicated something went wrong, and so on. Now we're moving back to that approach. It's funny to see the cycle repeat
@Masterrunescapeer4 ай бұрын
Cool that it's part of C# implementation, still not that much of a fan unless you're planning to handle it one level higher, performance overhead for exceptions are minimal no matter how you argue it as it's an exception. Prefer having a proper stack trace for errors and let the layer that's responsible for it handle it, not permeate layers and layers of Result returns, just obscures code and every single layer you keep having to write stupid if checks. Jon Skeet: "If you ever get to the point where exceptions are significantly hurting your performance, you have problems in terms of your use of exceptions beyond just the performance."
@valterszaluzinskis24534 ай бұрын
result types are realy good, and they opens opportunity to go step further and use railway programming, which allows to write code like it is always on happy path
@MightyNicM4 ай бұрын
Man C# slowly becomes the new C++, it combines every possible paradigm and as a result, gets more and more convoluted.
@evancombs51594 ай бұрын
Yeah, I would like to see Microsoft create a more refined language based on C#, kind of like what Kotlin is to Java.
@yuriy53764 ай бұрын
@@evancombs5159 why not just use C#6-C#7 - when it hadn't yet become a syntactic diabetic.
@EdKolis4 ай бұрын
I thought Kotlin was the love child of a time traveling Java and a future version of C# 😂
@michael-tsai3 ай бұрын
All this kind of fancy new C# features are pushing me towards Golang.
@Mortizul4 ай бұрын
I've been using language-ext since 2017 when I started working for the guy who wrote it. It's a very nice way of coding but once you start working with monadic types, they do propagate throughout your code base and if that's not acceptable to your team, IMO the benefits become limited. I'm excited to see how the C# team implement this in the BCL!
@AJax20124 ай бұрын
I'd be curious to see what the performance difference is between this and a library that avoids exceptions all together (like ErrorOr). It looks like you'd still need to create exceptions here but I thought the slowest part of excpetions was generating the stacktrace? Maybe I'm wrong...
@tomohisatakaoka4 ай бұрын
We like it , we need this feature in C#
@caunt.official4 ай бұрын
What will happen to nesting methods? I have a method call tree with depth of 5 methods, each can return multiple errors. So how do I pass the original error up to the caller? Also will caller be forced to handle ~30 possible errors? Or can it just handle all them in once, like catch(Exception) did?
@evancombs51594 ай бұрын
The spec isn't complete in the proposal, but it should be something like this: Result result = doSomething(); if (result.IsFailure) return result.Failure; //Else Continue Processing As well, I would recommend moving away from so much nesting of methods. Instead use an orchestration pattern. It will result in a much easier to understand codebase.
@MarcelPopescu3 ай бұрын
@@evancombs5159 The orchestration pattern makes sense for distributed code, but it's dangerous for code in the same project. It's basically a method call without the compiler helping you with anything, sooner or later you're going to forget to change things properly in one place. We want to move from runtime errors to compiler errors, not the other way around.
@evancombs51593 ай бұрын
@@MarcelPopescuwe must be talking about two very very different things. I'm talking about not nesting, no idea what you are talking about.
@rumplin2 ай бұрын
Will be fun with IOption (for appsettings) and Option (monad)
@TheKoneko13124 ай бұрын
The one thing I REALLY wish for is letting us put multiple errors in a single result. Domain validation could then be handled by tje result type and not needing an external library or custom class.
@evancombs51594 ай бұрын
I think in most cases inheriting from an IError or abstract Error type would be sufficient to switch on any subtype. Unfortunately the proposal does lack a little bit in the details, but that is how I always handle errors when I use a result class. It is how it should work if implemented correctly.
@DisturbedNeo4 ай бұрын
"Will the Option and Result" type also include the monadic behaviors?" "No, C# will not include any monadic behaviors in the language for these types at this time." Sounds like they're going to be difficult to use, even with DUs.
@gliaMe4 ай бұрын
So does an exception has to be passed into the Result object in the invalid case or can it be anything? If it is an exception, it is not actually thrown and thus has no callstack?
@evancombs51594 ай бұрын
You do not use exceptions. Exceptions are for errors in your code or errors outside your control (like losing network connectivity). Instead you would return some kind of error object that details what is wrong with the data being processed.
@jonasbarka4 ай бұрын
I think these are best for expected errors, like trying to add a duplicate user. No need for a call stack, it only slows things down. If an exceptional error happens, throw an exception. The callstack is useful for fixing a potential bug that caused it.
@jimlynchcodes2 ай бұрын
Minor nitpick, but with the Option type the point is not that you HAVE to handle both cases- it's just that you have to ACKNOWLEDGE that it COULD have the other state by having to unwrap it (for example, "if let" in Rust is what could use if you actually only wanted to handle one case or the other. not sure if c# has that)
@szikig4 ай бұрын
How does it differ from this ? OneOf
@dbpieter4 ай бұрын
it doesn't
@fusedqyou2 ай бұрын
`Result` returns either a result or an exception. OneOf can return multiple results, and optionally one or more can be an exception.
@GameDevNerd4 ай бұрын
The new Result/Option types I think (at least from my point of view) are being added now to facilitate better code for both AI models and servers/web. C#/.NET is finally becoming a 1st class language for AI development and made huge strides in the past few months, and one area that's a bit problematic for strongly typed languages is all the disparate shapes and types of structs and tensors. It can force you to have to use managed code and reflection and things that aren't optimal for inference performance. The traditional way around that is try to hack together special interfaces with `unmanaged` constraints and use pointers, but that gets rather complicated.
@iliqnikushev38204 ай бұрын
What i have made in my codebase is a Roslyn Transpiler for the Result. Whenever it finds a method throwing an exception it wraps it in a Result, replacing all throws with the new Result(...), and into a new concrete class, (code stays the same, just wraps the throws) When i create an instance of the UserService, i create it with ServiceCreator.Create() which by default will return a UserService, but if the transpiler picked it up, it will have created a ExceptionWrappedUserService The ServiceCreator.Create is a static class which has a basic Create method and whenever a new type is added, there is now the new Create method Can we just have this in C#'s compilation pipeline and skip the boilerplate? Imho, we should write code as we would normally (with exceptions), and there should be a step before the compiler to manage syntax sugar, if we enable a flag :)
@paramjotsingh40194 ай бұрын
I literally learned and created my own implementation of result pattern 3 days ago...
@verdurakh4 ай бұрын
Very nice, now I just wish I wasn't stuck working in Framework with strict rules on third party libs I can use
@andriiyustyk93784 ай бұрын
What about the exception logging? Now if some code base has its own Result class, usually you can't see a stack trace of the error/exception. On a big project, it's a pain, to look for a place where error/exception has occurred.
@MRender324 ай бұрын
I can already feel how painfully the Option type is going to interoperate with nullable reference types and Nullable
@ErikBongers4 ай бұрын
There are so many languages out there nowadays, and it seems most of them are adopting the best features of each other. Quite exiting days...although still a bit of a jungle. And I feel bad for C and C++, they served well and deserve our respect.
@sneffetsd4 ай бұрын
This is really cool!
@wizarrc4 ай бұрын
I think that at the runtime level, nullable types and option should be equal if a strict mode is enabled to allow existing libraries to produce option types for consumption without them having to change their api signatures, then with strict mode enabled, do not allow anything null, everything has to be wrapped in option types. Same concept for exceptions with result, only problem is this isn't Java where exceptions are known in the api signature. So if that's the case, first start tracking what kind of exceptions a function/method can throw and then apply this auto-conversation to result type once if opted in and library supports it.
@BlTemplar4 ай бұрын
The biggest problem with null is that the runtime can’t tell the difference between new Class and new Class for Class. This information is erased at the compile time. Class and Class are on the other hand different and they should be different. Option is a full-fledged type, not some compiler workaround.
@user-tk2jy8xr8b4 ай бұрын
Nope, having Option is required in some cases. Obviously Nullable and ref types do not support that
@hbjoroy4 ай бұрын
Hope it will be low level compatible with f#, so that the clr can evolve to much more robust apis, and so that interoo between c# and f# gets easier. Result, option and other DU interop is very tedious today.
@Suriprofz4 ай бұрын
Love either monad, a bit like option and match in rust. Wich still feels cleaner tho
@shakoomalo4 ай бұрын
If the validations are in a separate void method and throw an exception if necessary, in this case it should return an object and check if this object has a value. It will be a little ugly
@kaidouz77564 ай бұрын
when building my API i came across this problem the returning result from API, the only simple way to handle it was to create a middleware exception to catch thrown exceptions if user doesnt exist or user already exists and so on... (unsucessfull flows), on the middleware exception i would create a object containing the StatusCode and the ErrorMessage and send it. when calling the endpoint i would check if successfull and wrap the response in ApiResponse, containing a property: T? Data if not successfull then i would know that there was error and based on the statuscode from the middleware response i could switch on the code and do whatever i want.
@davidbloom73654 ай бұрын
Does the new Result type render libraries like FluentResult obsolete?
@GrzegorzGaezowski4 ай бұрын
I'm probably gonna use Result very seldom. I'm scratching my head how this type became so overhyped where its usefulness is really limited in OO code. I'm especially confused when I hear people say that they replace exceptions with Result (bad idea unless exceptions were used for flow control) or return Result from methods which have side-effects (bad idea because it violates CQS).
@Miggleness4 ай бұрын
Yep. i’d skip this pattern until I have a really good reason to do so.
@pedrocunha43224 ай бұрын
It would be interesting to check how much performance boost we will have in the dotnet 9
@nothingisreal63454 ай бұрын
It will be minimal.
@rcherrycoke73224 ай бұрын
Been waiting for Microsoft to add this to c# - glad it’s finally going to happen
@KasperSOlesen4 ай бұрын
Maybe you can add the Switch feature to the option with extensions until its officially implemented? I use extensions quite a bit, but I have not tried adding a switch to something so I am not sure if its possible but I am pretty sure something could be done that would make it nicer looking and explains itself better. The match methods main problem for me is that its not especially obvious that the second option happens when "not matched". The switch would make it cleaner I think while it probably also helps describe the different cases. I agree that its great that it is added. I myself do not enable the "enforce nullable types" in my projects, and I do use nulls a lot, but I also know that I really should avoid nullables and I do often end up having crashes and other strange problems simply because I still use classes, properties and so on that can be null. So when making packages for others to use, I can see why it would help ensure that they run into fewer problems by enforcing this, and also exceptions as a common way of dealing with certain events that you know are common is something I would think best to avoid. As I think you mentioned, exceptions adds a performance hit. If that was not the case I would be less against using exceptions so commonly. But I still use exceptions myself and try catch, and many times its the null properties that cause the exceptions in my code... so... I really should work more on my code ethics.
@recycledsoldier4 ай бұрын
This is a minor nitpick, but I'm not a huge fan of the name "Option" as we use the same word to describe other elements in the code. A lot of static code analysis will also throw errors if you have code that uses a library name like Attribute so I could see this causing issues. Just seems like there could be some nomenclature collision with the options pattern. I would have preferred Optional or HandledResult or something more descriptive.
@jonasbarka4 ай бұрын
It's an already established name.
@recycledsoldier4 ай бұрын
@@jonasbarka I get that. It’s just annoying as there’s possible name collision caused by this. It’s also not super descriptive as to what it’s doing. Generally an option is a configuration
@SunriseTequila5234 ай бұрын
Will it only be possible to return error as exceptions? As you said Nick, it is very expensive to throw exceptions
@alexanderbecker73994 ай бұрын
The exception is created but not thrown. Side effect: ex.StackTrace will be null...
@SunriseTequila5234 ай бұрын
@@alexanderbecker7399 maybe they will find a way to distinguish between exceptions and errors, because for me exceptions are really "heavy" events, like a db connection is lost... But validation for me is an error, a lightweight to let the developer know that something wrong happened but it's not critical
@asdqwe4427Ай бұрын
This would be great
@alex-bj1il4 ай бұрын
Will they migrate the standard library to union types? That seems quite unlikely, considering the amount of code that already depends on exceptions.
@sacalbal4 ай бұрын
One question : is result (or a variant) serializable ? Because i often use a custom ResultDto to return a result from a web service call, with an error message instead of an exception. It could be interesting to have a standardized result object for this usage.
@aurinator4 ай бұрын
AFAIK Rust's Tokio Crate started these Types.
@AkosLukacs424 ай бұрын
Maybe a bit earlier. Discriminated unions were in algol back in the 1960's according to Wikipedia Later in ML, ocaml and therefore they are in F# since forever :)
@Ziplock90004 ай бұрын
I've always done this myself with my own system rather than using exceptions anyway.
@ml_serenity4 ай бұрын
Just a proposal still... But we can hope we get more functional goodness in C#
@user-tk2jy8xr8b4 ай бұрын
Technically those two new types are not going to be monads OOB because they lack Map and Flatten (maybe Pure as well). Extension methods can help with that though.
@mrstiflor67444 ай бұрын
Ok the Result type is neat
@armanradan4 ай бұрын
They use 'match' instead of 'switch' because this feature is inspired from Rust and 'match' is the way to handle enums, results and options in Rust.
@khealer4 ай бұрын
Option is good for Database access. You can now represent NONE (missing). Before you only had NULL or NON-NULL. If I understand how it works correctly.
@SirBenJamin_4 ай бұрын
A question regarding exceptions. You mentioned that they were incredibly slow. Is this only in the case where you have try/catch handling? The reason I ask is because exceptions are used everywhere in the base class libraries. So in reality, what performance difference is it going to make if they're still used heavily in the underlying code?
@BlTemplar4 ай бұрын
Exceptions are slow when you use them for the control flow. Imagine you have an API available for a lot of consumers and you have some SLA on the response latency. Something goes wrong, you throw the exception, catch the exception, do some handling, throw it again and finally catch it in the response middleware. It is much slower than just using Result pattern and returning the response directly. The difference between exceptions and Results won't be very noticable on low RPS but as soon as you hit high RPS you will definetly experience latency spikes if you throw a lot of exceptions. As for standard libraries, they don't normally throw exceptions.
@jackkendall64204 ай бұрын
The slow part is dealing with the stack when catching exceptions. Entering a try-block has some performance implications, but quite minimal ones. Besides those things, exceptions are just normal objects.
@BlTemplar4 ай бұрын
@@jackkendall6420 Yep. Fun fact you can throw exceptions in Java without capturing the stack trace.
@SirBenJamin_4 ай бұрын
@@BlTemplar ah ok. So a method having the code to throw exceptions when something is wrong (e.g argument exceptions) isn't the slow part, it's only when an exception is thrown and has to be handled is when it becomes slow? What I am asking I guess is .... would the generated code be more efficient if it didn't need to support throwing exceptions.
@BlTemplar4 ай бұрын
@@SirBenJamin_ not really, throwing is the most expensive part because you have to capture the call stack. You don’t usually need the call stack for the business logic errors. Business logic errors can happen often and if you use Result instead of Exception you also get better performance.
@IcaroFelix20234 ай бұрын
Could you some day make a video about the library C# Functional Extensions ?
@서영준4 ай бұрын
It's a shame that we don't have the 'static implicit operator Result(Exception e)'
@Rein______4 ай бұрын
I hope Option will have a .Map function just like the Optional in Java.
@RomainLagrange14 ай бұрын
Hi nick, it would be awesome if we could use the result in a basic if/else statement, because going lambda in a suit of operations will lead to nested lambdas... a pain in the ass to read...
@cristiz-vf4ww4 ай бұрын
How do you chain calls when the function returns Task of something?
@TheRAINMan0594 ай бұрын
await and use parentheses
@adambickford87204 ай бұрын
If the c# devs are anything like java, this will be met with pitchforks and torches.
@peculiar-coding-endeavours4 ай бұрын
Luckily, they are not (that's me hoping)
@shadowsir4 ай бұрын
as a previous full-time F# developer, Result was the first thing I added to C# in our codebase.
@peculiar-coding-endeavours4 ай бұрын
@@shadowsir lol same, I think many people did that over the years, and the number of nuget packages that do this are getting more and more numerous, so I think that triggered Microsoft to think about adding it natively.
@cew1824 ай бұрын
Yeah, I've seen a lot of requests for it. So I don't expect the pitches and torchforks
@BlTemplar4 ай бұрын
It's a very funny comment because Java has had Option for years and has recently added type unions with switch pattern matching as well. You can create Result type and use switch to match over Success or Failure in Java today already. The syntax sucks as usual but Java type unions (called sealed interfaces in docs) are exactly what C# class type unions will be.
@sealsharp4 ай бұрын
Nice, please steal comptime next.
@_simoncurtis4 ай бұрын
We would basically have unions already if they had a way of allowing you to extend the `switch` logic for your type. Like IEnumerable in `foreach`
@meirkr4 ай бұрын
Is ir possible to switch on the Result same as on the Option?
@theideaot4 ай бұрын
Hey, I hear you like rust so much that we added some into c#, in which you actually work and get paid for. Better still wrap it in try-catch though - it's still c#
@Robert-yw5msАй бұрын
Imo you don't really show the benefit of Option which is the bind method. This allows you to chain a whole load of operations without worrying about the None/null situation until the very end.