Aliases are helpful in these situations using Users = ;
@bigice71845 ай бұрын
Lol I think people are just going to put that into a new interface to short method signatures back to normal levels.
@_iPilot5 ай бұрын
Empty enumerable is enough instead of Option. Do not return null instead of empty collection. Nick also mentioned that few times.
@cj82-h1y5 ай бұрын
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.
@WDGKuurama5 ай бұрын
@@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.
@deeplerg79135 ай бұрын
Nick is gonna milk this proposal for 10 more videos
@nickchapsas5 ай бұрын
You have no idea
@peculiar-coding-endeavours5 ай бұрын
As he should
@smorebytes5 ай бұрын
As he should.
@sohn77675 ай бұрын
As he should
@Ruisrd5 ай бұрын
As he should.
@Crozz225 ай бұрын
I'm so happy you emphasize so much the importance of exhaustiveness and forcing yourself to handle all cases.
@michaeldileo19545 ай бұрын
One tip with LanguageExt options, you can switch on the Case property: Option.Case switch { User u => …, null/_ => … }
@Masterrunescapeer5 ай бұрын
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.
@dennisr9995 ай бұрын
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-u5k5 ай бұрын
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.
@tarquin1612345 ай бұрын
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.
@projectuber5 ай бұрын
@@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.
@leerothman27155 ай бұрын
@@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.
@alexclark67775 ай бұрын
'bout time C# grew a pair of monads
@asdfxyz_randomname21335 ай бұрын
never realized that monads sounds like gonads...
@aurinator5 ай бұрын
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.
@mbpoblet5 ай бұрын
C# has had monads for a long time... LINQ's built out of them.
@AdrianoKretschmer4 ай бұрын
lol, I see what you did there...
@Sayuri9985 ай бұрын
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.
@nommet5 ай бұрын
Guaranteed bug fixes 😆
@GeorgeGeorge-u5k5 ай бұрын
I tottally disagree. We are bloating .NET with pointless features. Bigger dlls, slower performance etc.
@SixOThree5 ай бұрын
@@GeorgeGeorge-u5k Thankfully you don't need to compile in features you don't use.
@gavinrolls10544 ай бұрын
@@GeorgeGeorge-u5ki don't agree that it results in slower performance
@mistrzmatik5 ай бұрын
Me: Nick, can I use Rust? Nick: We have Rust in C# Rust in C#:
@ochronus5 ай бұрын
10/10 meme usage :D
@jongeduard5 ай бұрын
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.
@GameDevNerd5 ай бұрын
// Rust: declares integer called "n" ×&÷>%>×&÷>÷[$*&$
@true_xander5 ай бұрын
@@GameDevNerdlooks very c++ to me
@ranggatohjaya54715 ай бұрын
let age: i32 = 0; 😊@@GameDevNerd
@patrickkurmann5 ай бұрын
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#.
@alexlo56555 ай бұрын
Me too. This is the great library.
@franciscorusso80625 ай бұрын
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.
@Kotz_en5 ай бұрын
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.
@Turko777773 ай бұрын
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
@joga_bonito_aro5 ай бұрын
Returning result objects was one of the best things I ever did to my codebase.
@BamYazi4 ай бұрын
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
@chrismantonuk5 ай бұрын
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.
@VitalMiguel5 ай бұрын
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.
@2SHARP4UIQ1505 ай бұрын
I agree. At my company, we fired all the QA teams and replaced them with pattern matching, with no more bugs.
@JollyGiant195 ай бұрын
@@2SHARP4UIQ150QA and this are both arrows in the quiver of excellence. Why would you fire them??? That’s insane
@LC123455 ай бұрын
Slowing people down and preventing them from pushing code is a way to reduce bugs too
@2SHARP4UIQ1505 ай бұрын
@@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. 😉😂
@tauiin4 ай бұрын
@@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.
@joshman10195 ай бұрын
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.
@WillEhrendreich5 ай бұрын
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.
@joshman10195 ай бұрын
@@WillEhrendreich It's a fantastic language! I pair it with C# to get a lot of stuff done, and I couldn't be happier.
@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)...
@Hawkeyes19835 ай бұрын
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!
@weicco5 ай бұрын
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.
@fusedqyou3 ай бұрын
Ah yes, reinventing the wheel.
@ricardobastos2425 күн бұрын
You complicated the code, The great challenge of programming and making things simple
@gileee5 ай бұрын
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.
@Sameer.Trivedi5 ай бұрын
At this point you C# has enough things to recreate the entire Earth from scratch.
@DaremKurosaki5 ай бұрын
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.
@zwatotem5 ай бұрын
It had from C# 2, but now there's 5 ways to do it!
@Sunesen5 ай бұрын
At this point, C# is pretty much turning more and more into F#. :P
@sleeper-cassie5 ай бұрын
The programming language equivalent of carcinisation is that languages keep evolving towards LISP.
@JollyGiant195 ай бұрын
@@sleeper-cassieLISP’s sin was always the those parentheses
@WillEhrendreich5 ай бұрын
as it should.
@bbqchickenrobot35 ай бұрын
Thats a good thing - loved F#. Minus the missing "protected" level access
@nooftube25415 ай бұрын
“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
@tarquin1612345 ай бұрын
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 .
@TehGM5 ай бұрын
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.
@Tsunami145 ай бұрын
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.
@ekhm5 ай бұрын
@@Tsunami14 How do you define exceptional situation? Trying to update not existing object isn't exceptional situation? It's not a "normal" path.
@nothingisreal63455 ай бұрын
On the other hand that "magic" implicit error handling somewhere else in the code reduces readability.
@BlTemplar5 ай бұрын
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-schmidt5 ай бұрын
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.
@LaszloLueck5 ай бұрын
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-tk2jy8xr8b5 ай бұрын
Result type has a built-in "success or error" semantics unlike Either which is just a sum without any additional meaning
@ekhm5 ай бұрын
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-endeavours5 ай бұрын
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.
@BlTemplar5 ай бұрын
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.
@damianradinoiu43145 ай бұрын
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
@chris200777775 ай бұрын
You mean the developer needs to decide how each function should return a particular result? How horrible!
@evancombs51595 ай бұрын
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.
@liquidpebbles5 ай бұрын
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.
@pavelmaskevich76112 ай бұрын
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
@NickSteffen3 ай бұрын
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.
@Raminiya5 ай бұрын
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.
@caunt.official5 ай бұрын
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?
@evancombs51595 ай бұрын
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.
@MarcelPopescu4 ай бұрын
@@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.
@evancombs51594 ай бұрын
@@MarcelPopescuwe must be talking about two very very different things. I'm talking about not nesting, no idea what you are talking about.
@Artokieffer5 ай бұрын
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-endeavours5 ай бұрын
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.
@ProbablePrime5 ай бұрын
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.
@JollyGiant195 ай бұрын
Result and Option objects are built for functional use so to use them without callback hell does necessitate a functional approach
@user-tk2jy8xr8b5 ай бұрын
LINQ syntax to the rescue
@ProbablePrime5 ай бұрын
@@JollyGiant19 That is fair, I just wondered if there was an approach that didn't use it.
@bbqchickenrobot35 ай бұрын
So excited foe the Result and Option - Now if we can get immutable variables by default!
@evancombs51595 ай бұрын
Immutable by default will never happen, too fundamental of a change for it to happen. You'll need a new language.
@jongeduard5 ай бұрын
@@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.
@evancombs51595 ай бұрын
@@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.
@jongeduard5 ай бұрын
@@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)
@tridy78935 ай бұрын
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.
@BlTemplar5 ай бұрын
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.
@tridy78935 ай бұрын
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.
@Masterrunescapeer5 ай бұрын
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."
@JeffKwak5 ай бұрын
Wouldn't `Result` be `Result` instead of `Result`??
@WillEhrendreich5 ай бұрын
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*
@aremes5 ай бұрын
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.
@gliaMe5 ай бұрын
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?
@evancombs51595 ай бұрын
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.
@jonasbarka5 ай бұрын
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.
@benmuse1405 ай бұрын
Very much looking forward to this being part of the runtime
@King21-t7u5 ай бұрын
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.
@szikig5 ай бұрын
How does it differ from this ? OneOf
@dbpieter5 ай бұрын
it doesn't
@fusedqyou3 ай бұрын
`Result` returns either a result or an exception. OneOf can return multiple results, and optionally one or more can be an exception.
@sazarkevich4 ай бұрын
I am on project with homegrown Option, Result and it is nightmare... It uses lambdas everywhere, and it is very uncomfortable to understand tens of indentations and nested lambdas. Refactoring cannot be done with tools, only by hands. Usually when I need to understand and modify (more or less significantly) some part of such code - I rewrite it to be more linear, understand logic and do modifications. But possibly Option/Result from video will be is more convenient, as it allow to use switch...
@benqbenq5 ай бұрын
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.
@AJax20125 ай бұрын
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...
@scottwalker46195 ай бұрын
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
@nothingisreal63455 ай бұрын
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.
@iliqnikushev38205 ай бұрын
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 :)
@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.
@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)
@mrwensveen5 ай бұрын
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.
@kaidouz77565 ай бұрын
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.
@carambanoescacharrado94463 ай бұрын
Amazing I hope they add it soon. 🎉
@Suriprofz5 ай бұрын
Love either monad, a bit like option and match in rust. Wich still feels cleaner tho
@ravikumarmistry5 ай бұрын
C# is slowly getting all the features that a functional code need in language itself
@Mortizul5 ай бұрын
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!
@recycledsoldier5 ай бұрын
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.
@jonasbarka5 ай бұрын
It's an already established name.
@recycledsoldier5 ай бұрын
@@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
@andriiyustyk93785 ай бұрын
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.
@davidbloom73655 ай бұрын
Does the new Result type render libraries like FluentResult obsolete?
@GameDevNerd5 ай бұрын
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.
@sacalbal5 ай бұрын
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.
@RomainLagrange15 ай бұрын
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...
@rumplin3 ай бұрын
Will be fun with IOption (for appsettings) and Option (monad)
@SebGruch5 ай бұрын
Good to see, that things that I'd introduced like 10 years ago, now go into language ;-)
@valterszaluzinskis24535 ай бұрын
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
@IcaroFelix20235 ай бұрын
Could you some day make a video about the library C# Functional Extensions ?
@cravecode17425 ай бұрын
Love the Result, not thrilled with Option. Still feels like T?.
@hbjoroy5 ай бұрын
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.
@verdurakh5 ай бұрын
Very nice, now I just wish I wasn't stuck working in Framework with strict rules on third party libs I can use
@wizarrc5 ай бұрын
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.
@BlTemplar5 ай бұрын
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-tk2jy8xr8b5 ай бұрын
Nope, having Option is required in some cases. Obviously Nullable and ref types do not support that
@TheKoneko13125 ай бұрын
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.
@evancombs51595 ай бұрын
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.
@alex-bj1il5 ай бұрын
Will they migrate the standard library to union types? That seems quite unlikely, considering the amount of code that already depends on exceptions.
@juliendebache83305 ай бұрын
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.
@shakoomalo5 ай бұрын
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
@CryShana5 ай бұрын
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
@deeplerg79135 ай бұрын
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.
@CryShana5 ай бұрын
@@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.
@sohn77675 ай бұрын
@@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.
@CryShana5 ай бұрын
@@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.
@CryShana5 ай бұрын
@@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
@pedrocunha43225 ай бұрын
It would be interesting to check how much performance boost we will have in the dotnet 9
@nothingisreal63455 ай бұрын
It will be minimal.
@user-tk2jy8xr8b5 ай бұрын
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.
@tomohisatakaoka5 ай бұрын
We like it , we need this feature in C#
@서영준5 ай бұрын
It's a shame that we don't have the 'static implicit operator Result(Exception e)'
@GrzegorzGaezowski5 ай бұрын
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).
@Miggleness5 ай бұрын
Yep. i’d skip this pattern until I have a really good reason to do so.
@DisturbedNeo5 ай бұрын
"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.
@MightyNicM5 ай бұрын
Man C# slowly becomes the new C++, it combines every possible paradigm and as a result, gets more and more convoluted.
@evancombs51595 ай бұрын
Yeah, I would like to see Microsoft create a more refined language based on C#, kind of like what Kotlin is to Java.
@yuriy53765 ай бұрын
@@evancombs5159 why not just use C#6-C#7 - when it hadn't yet become a syntactic diabetic.
@EdKolis5 ай бұрын
I thought Kotlin was the love child of a time traveling Java and a future version of C# 😂
@michael-tsai4 ай бұрын
All this kind of fancy new C# features are pushing me towards Golang.
@drax4325 ай бұрын
Hi, newbie in C#. The Option demonstrated in this video is native part of C# language, or it is only available via third party library? If Option is not part of C#, does microsoft has any plan to include that natively?
@cristiz-vf4ww5 ай бұрын
How do you chain calls when the function returns Task of something?
@TheRAINMan0595 ай бұрын
await and use parentheses
@sneffetsd5 ай бұрын
This is really cool!
@JonathanYee5 ай бұрын
Java's Optional anyone? And Golang return convention? Not a fan of the method calls for this though. It just makes way more indentation in my code but then again I guess its the same as if statement indentation🤷♀. But i'd rather use those primitive syntax.
@khealer5 ай бұрын
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.
@victorfox29725 ай бұрын
Hey Nick, I don't know if you covered csharpfunctionalextensions library before, if not I think you should!
@cew1825 ай бұрын
kzbin.info/www/bejne/j5PYhKiJpd-Ym5Y
@SunriseTequila5235 ай бұрын
Will it only be possible to return error as exceptions? As you said Nick, it is very expensive to throw exceptions
@alexanderbecker73995 ай бұрын
The exception is created but not thrown. Side effect: ex.StackTrace will be null...
@SunriseTequila5235 ай бұрын
@@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
@_simoncurtis5 ай бұрын
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`
@Robert-yw5ms2 ай бұрын
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.
@sealsharp5 ай бұрын
Nice, please steal comptime next.
@DayMan85Theater5 ай бұрын
What I don't like about this `Result` type is that the non-success case must be an `Exception`, and the idea of returning an `Exception` that was never thrown doesn't feel right to me. I have been using and enjoying the LanguageExt library recently, but I prefer to use `Either` where the "left" type is LanguageExt's `Error` type, which may wrap an `Exception`, or may just represent a "non-exceptional" custom error. Small downside is that I have to explicitly specify `Error` every time, which does result in verbose return types like `Task`. I kind of wish that `Result` would just swap out `Exception` for `Error` as the non-success case.
@SirBenJamin_5 ай бұрын
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?
@BlTemplar5 ай бұрын
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.
@jackkendall64205 ай бұрын
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.
@BlTemplar5 ай бұрын
@@jackkendall6420 Yep. Fun fact you can throw exceptions in Java without capturing the stack trace.
@SirBenJamin_5 ай бұрын
@@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.
@BlTemplar5 ай бұрын
@@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.
@ErikBongers5 ай бұрын
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.
@gl0ckalacka5 ай бұрын
So are we going to see *Option and *OptionAsync variants of existing methods added to the runtime and aspnetcore? Will Microsoft library design stop producing NRTs as return types in favor of Option if this goes through?
@Tsunami145 ай бұрын
That's a very good point. As interested as I am in the Option type, the null pattern is codified quite deeply into the bcl, so there'd likely (understandably) be a lot of mixing of these 2 styles within our own code bases.
@aurinator5 ай бұрын
AFAIK Rust's Tokio Crate started these Types.
@AkosLukacs425 ай бұрын
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 :)
@PereViader5 ай бұрын
I really like the Result type, but I don't currently see the point on the Result type. Nullable annotations should be the way to do it. The only problem with nullable is Generic value nullables don't handle default values properly
@meirkr5 ай бұрын
Is ir possible to switch on the Result same as on the Option?
@michalfillo5 ай бұрын
so it is basically the same as ErrorOr?
@casperpieterseАй бұрын
Result is getting removed in v5 - should probably not advocate it going forward.