What’s the Result Type Everyone Is Using in .NET?

  Рет қаралды 99,150

Nick Chapsas

Nick Chapsas

Жыл бұрын

Check out my courses: dometrain.com
Become a Patreon and get source code access: / nickchapsas
Hello, everybody, I'm Nick, and in this video, I will introduce you to the Result type in .NET. It might not be a native .NET type but it exists in tons of libraries and codebases so in this video I'll help you understand why.
Workshops: bit.ly/nickworkshops
Don't forget to comment, like and subscribe :)
Social Media:
Follow me on GitHub: bit.ly/ChapsasGitHub
Follow me on Twitter: bit.ly/ChapsasTwitter
Connect on LinkedIn: bit.ly/ChapsasLinkedIn
Keep coding merch: keepcoding.shop
#csharp #dotnet

Пікірлер: 258
@nmacw93
@nmacw93 Жыл бұрын
I ended up using this concept in C# after working with Rust which has a Result type built in and have found it a great way avoiding throwing exceptions everywhere.
@EEEdoman
@EEEdoman Жыл бұрын
Definitely cover more functional stuff! This kind of content is exactly what we love to see, practical application of functional concepts.
@SifSehwan
@SifSehwan Жыл бұрын
We've been using this for years combined with a railway pattern which makes it more functional. I hated it in the beginning, but has since become my preferred way of coding.
@orterves
@orterves Жыл бұрын
The difference is all the pain is upfront instead of spread out over years of production bugs. So really the decision of using the result type is down to whether you reckon you'll still be working on the code in a year or two...
@local9
@local9 Жыл бұрын
Today is the first time I've heard of "railway pattern", why does this make so much sense.
@dolgan12
@dolgan12 Жыл бұрын
Welcome to F# :)
@SifSehwan
@SifSehwan Жыл бұрын
@@dolgan12 While I love this way of writing code, I can't subscribe to any love for F# in it's current form. And that's purely personal rooted in habit.
@gileee
@gileee Ай бұрын
@@orterves This method is error prone if someone fails to check for result.IsError before using it. So you still have the same issues as when someone fails to handle an exception. Which means you still have to wait for exceptions to present themselves in production. So what are you avoiding exactly? The only benefit of this approach is performance (since exceptions in C# are really slow), and more explicit code (which doesn't necessarily make it less error prone, only easier to follow when you're tracking down errors).
@MetalKid007
@MetalKid007 Жыл бұрын
I've used this sort if pattern for over 10 years and it has never let me down! :)
@iuribrindeiro5009
@iuribrindeiro5009 Жыл бұрын
This is probably a better introductory video: kzbin.info/www/bejne/i4SbgnpvfpaLjZI
@umairbutt1355
@umairbutt1355 Жыл бұрын
I would recommend the C# functional extensions library by Vladimir Khorikov. It has this as well as loads of helper extension methods such as Tap, Bind, Map etc. I love it!
@Cristian-ek7xy
@Cristian-ek7xy 11 ай бұрын
Our team is using it as well
@parlor3115
@parlor3115 Жыл бұрын
I use this pattern myself but it's miles behind of what it can be if C# only had discriminated unions. For example, we wouldn't need an fancy Match or Map or whatever. Just a simple type comparaison in a guard clause and you'd only be left with the "happy path", assuming the language also supported exhaustive type matching (aka the compiler is able to deduce the state the result is in based on context).
@CecilPhillip
@CecilPhillip Жыл бұрын
I'm a big fan of this approach. I used to write similar classes like that years ago when I was working on web forms applications. The Good Old Days 😂
@brianviktor8212
@brianviktor8212 11 ай бұрын
I've made a general Result type to encompass all general situations. It allows the caller to handle success state and a raised exception. There is also Result and Result in case return values are desired. It's only ~300 lines of code though. There are 3 outcomes: Success, Failure, Exception. It also has implicit operator for convenience.
@gveresUW
@gveresUW 11 ай бұрын
I have been using my own ResponseType for a few years now. It has made all of my controller functions 2 lines, one to call the api method that implements the controller and one that transforms the ResponseType into the IHttpActionResult. My implementation is nowhere near as fancy as the one you illustrated. I don't really see the need for any of those extra features, but I am sure they are useful for someone. I did make a change to my ResponseType class after watching the video though. I changed it from a class to a readonly struct. That's a nice improvement.
@andyfitz1992
@andyfitz1992 10 ай бұрын
I remember doing somerthing similar to this years ago with classes that encapsulated the success error, I was under the impression this design pattern was called 'rail-road' programming where you direct the flow of the application based on the result value of the previous call within a stackframe, I added a few extensions allowing the coder to fluently return control to the calling stack frame and depending on the framework bubbled up the result of the call.
@DryBones111
@DryBones111 11 ай бұрын
I've been using a self-rolled version of this for a while. I don't throw exceptions anymore. I think it would be great to show off the other main benefit to upgrading error state to a first class citizen and using these union types, which is the ability to glue together several operations. Specifically show off the ability to bind, and also the power of map in the result type context and how you can abuse LINQ query syntax with it.
@scottroberts7693
@scottroberts7693 Жыл бұрын
Known of this approach for years, but with the advent of clean code and driving logic flow through the use of exceptions, it is great to see this being spoken about again, especially in the terms that results are either "It worked" or "It didn't work". We miss that basic premise so much.
@Mortizul
@Mortizul Жыл бұрын
Yeh I was using this library in 2016 but now you can't get a job unless you program in the exact way that Uncle Bob says.
@scottroberts7693
@scottroberts7693 Жыл бұрын
@Mortizul but that's a problem in the making. Nothing wrong with convention or best practise, but maintainence, understanding, and reality kick in. It may make things cleaner but does it provide totally clarity, but overall we deal in logic 1s or 0s, true or false Soap box getting off, it also makes the complex seem simpler, but at an expense
@shelbytimbrook2095
@shelbytimbrook2095 Жыл бұрын
I've been using a self-made ApiResult class that solved this problem a long time ago. I don't have the implicit operators though; that definitely would make it much easier and more convenient to use.
@user-gn7bd6mq8n
@user-gn7bd6mq8n 3 ай бұрын
would u plz share ur ApiResult class?
@mindaugasw
@mindaugasw 11 ай бұрын
What about when the error happens somewhere deep inside the codebase? E.g. class A uses class B, which uses C, which uses D. If an error happens in class D, then you need to handle it in all classes C, B, and A, right? And what if class D has many methods with many possible errors, then you also need to handle all of them in all other classes? With traditional exceptions you could just throw an exception in class D and catch it in class A. Then, if it's an exception you expect (e.g. validation error) you can properly handle it and show validation errors to the user. Otherwise you just return generic 500 server error response. That seems much simpler, even if not as robust as using Result type. So I really don't understand how Result type could make your code better in a huge codebase.
@user-fu6mp6et8p
@user-fu6mp6et8p 8 ай бұрын
Agreed.
@softcodeacademy
@softcodeacademy Ай бұрын
Exactly. Argument against throwing exceptions is “exceptions are expensive” and argument against Result types is “there is a lot of checking”. I personally prefer throwing exceptions because I can just throw exceptions and be done with it.
@twiksify
@twiksify 10 ай бұрын
Have a peek at rust Option and Result for some other useful extensions which are quite simple to implement yourself.
@mzeeshan
@mzeeshan Жыл бұрын
I wrote my own Result type using SOLID + functional programming approach in C# back in .NET 4.8 days. Recently I have used that type in one of my commercial projects at work and it works like a charm.
@glennstartin8575
@glennstartin8575 Жыл бұрын
So glad you used LanguageExt ... I hope more demos of this package in the future, so many of its features have been adopted to the language officially.
@anreton
@anreton Жыл бұрын
Language ext is a good and functional library, it's true. But when using such tools, another important story often comes up - serialization. Some libraries have additional extensions (such as JSON serialization), but some others do not. This is an important point, which would also be very useful to highlight. PS. Nick, thank you very much for the useful and very valuable materials and videos that allow you to discover new things and tools, which allows you to be a more effective specialist.
@al-doori2392
@al-doori2392 Жыл бұрын
There is no way you uploded this now, I was looking at your video about (Don't throw exceptions) and I saw Result class and also was watching Amichi Error handling video, and just wanted to understand the Result class more, and now ....... wow Thank you a lot.
@vivekkaushik9508
@vivekkaushik9508 Жыл бұрын
Lol same. I was also watching his same video and actually looking if he had a video on Results.
@cjamesrohan
@cjamesrohan Жыл бұрын
Thanks Nick! I have a rudimentary library following the same basic concept of the Result struct from LanguageExt lib. The one difference I have that they don't is the implicit operator for the failure path as well, and it's SO NICE to be able to return either a new SuccessObject() or a new CustomException(). I also have some ResultExtensions designed to handle IActionResult responses in a similar try/catch fashion. But instead it's more like _methodAsync().HandleSuccess(x => successPath).HandleException(x => failurePath). And you can chain HandleException until finally calling ReturnAsync. I'd be curious on your thoughts Nick!
@michaelrall8142
@michaelrall8142 6 ай бұрын
interestingly I had that talk with an apprentice some days ago, where talked about the different options to return state and control flow. Turned out to be a quite large topic :-), personally I tend more and more towards Result-Objects, exactly because of the reasons you outlined.
@DrHeinzDoofenshmirtz
@DrHeinzDoofenshmirtz Жыл бұрын
I have jumped on this Flow Control as well with the ErrorOr library which is awesome! It supports returning multiple errors as well.
@Danny1986il
@Danny1986il 11 ай бұрын
It depend on BCL functions or 3rd pary libraires that you are using not throwing exceptions themselves. It ends up you are either creating 3 possible paths (value, exception as value, stack unwrapping exception), or having to wrap everything in try catch blocks. IMO this approach makes sense only in languages where exceptions by value is the only error mechanism.
@MrNachosVIDEOS
@MrNachosVIDEOS Жыл бұрын
Instead of using Result you better make use of OptionalResult This way we can make dealing with cases for Some, None and Error more declarative and get rid of possible nulls But one of the bad sides of the LanguageExt package is that it blocks the possibility of using NativeAOT nor Ready2Run That happens because this package heavily relies on source generation and it produces blockers for trimming and optimization of the IL code Also, the binary size of this package is massive (about 8 MB) So, if you want to use it in your production project you should take this into consideration Still, very nice approach for discriminated union type and functional style code in C#
@neociber24
@neociber24 Жыл бұрын
But isn't that the purpose of nullable types?
@MrNachosVIDEOS
@MrNachosVIDEOS Жыл бұрын
@@neociber24 True. But nullable type can let you ignore the potential null as an outcome. Nowadays, null can help with interconnection with C APIs and other third party stuff. Also, nullable type handy when you want to optimize internals of your implementation. But in terms of pure C# API it's meaningless and good plant for potential bugs. Same goes for interface: if your interface has a null for specific type as an potential outcome - this is a code smell
@HartzFEAR444
@HartzFEAR444 Жыл бұрын
5:16 "I'm gonna link them in the description below" - you forgot :(
@dcuccia
@dcuccia Жыл бұрын
Yes! More functional discussions, please!!
@damiantedrow3218
@damiantedrow3218 Жыл бұрын
Lol, I just faced this issue for a service I was calling. The framework could throw (timeout, 404, 500 etc), or the service returns valid or invalid. I invented this very solution to solve it to prevent control of flow problems in my calling code. I like how this uses matching for ensuring callers know what they need to handle.
@user-km7fd2le8f
@user-km7fd2le8f Жыл бұрын
Yes, I'd love a video about functional concepts like Some, None, Unit, etc.
@timschwallie1589
@timschwallie1589 Жыл бұрын
Yep, been doing this for a long time. Avoid throwing those exceptions! Though, I would avoid using the word 'Error' or 'Errors'. Usually see a non-passing Validation worded as a 'Breach' or 'Fail'. Also, need enough data stored so can send down the standard format for 400's.
@jamienordmeyer4345
@jamienordmeyer4345 Жыл бұрын
What I've done is something similar to this. My result type uses an Enum for the status, and an IEnumerable for any messages that I want to return. I then have an extension method in my API project (I tend to use the Clean Architecture pattern, so my result type definition lives in the Application layer) that converts the result type to an IActionResult, depending on the status and data in the result type. It's worked really well so far.
@hhgforfhuv
@hhgforfhuv Жыл бұрын
hello, could you please give me the link to the code about this idea (converting object result to IActionResult)
@jamienordmeyer4345
@jamienordmeyer4345 Жыл бұрын
@@hhgforfhuv I don't have a link about this at the moment, but I'll write up a blog post in the next couple days and give you that link. :)
@Aralmo640
@Aralmo640 11 ай бұрын
I do love the result approach, specially when coupled with linq syntax to avoid the nasty nesting it usually creates.
@nooftube2541
@nooftube2541 Жыл бұрын
Also you can use Try...(out result) patter. You can also add out failure to signature if you need.
@fsharpfan
@fsharpfan 11 ай бұрын
Has anyone else noticed that many of the new features in C# are from functional languages? F# has Result type and you can write result computation expression in few lines and then you do not deal with errors in your code. Of course you'll need to catch exceptions when you'll call code outside of F# and match result with Ok and Error later. F# is a great language!
@AnythingGodamnit
@AnythingGodamnit 10 ай бұрын
This is not a new phenomenon. Many of C#'s features were inspired by F# equivalents, and often F# was inspired by other ecosystems. async, switch expressions/pattern matching, records, etc. It's a shame more .NET devs don't try F# because there are a slew of important features - and a different way of thinking about programming - that simply cannot ever translate into C#. And, in fact, I'd argue that C# is getting more and more complicated trying to bolt on these things that are not a natural fit due to its inherent design philosophy.
@fredericbrown8871
@fredericbrown8871 5 ай бұрын
@@AnythingGodamnit It's not that new indeed as I've been using delegates/anonymous functions as lambdas since the mid 2000s (I think it was C# 2.0). It was clunky to use back then but I had a FP course at the university and was very eager to use all those slick patterns to solve real problems at work. C# is showing its age and some new features have rough edges or look bolted on indeed (one of the saddest causality is how NRTs are handled - better than nothing though!) but overall, the language doesn't feel all bent out of shape to me and most FP features added over time are really convenient and pleasant to use.
@dcuccia
@dcuccia Жыл бұрын
Great video, thanks. Look forward to a day where we can use switch expressions with DU deconstruction.
@nathancurnow2410
@nathancurnow2410 Жыл бұрын
I really like that you pretty much just reimplemented the Rustlang Result enum. Great work!
@saffronomicon
@saffronomicon 7 ай бұрын
I like the pattern because provides a consistency to a common problem and cleaner code, but it adds some debugging and readability overhead that I would like to see an improvement on.
@Mazzphysics
@Mazzphysics Жыл бұрын
I will def try it in my own projects.
@nooftube2541
@nooftube2541 Жыл бұрын
Looks developers of this lib didn't have enough letters... otherway I can't explain how they decided to name method "IfSucc" ...
@ryan-heath
@ryan-heath Жыл бұрын
If it succs then it is okay 😅
@iuribrindeiro5009
@iuribrindeiro5009 Жыл бұрын
Could you please make a video about this pattern in F# vs C#? Just to people know what we are looking for in C# by using this.
@obinnaokafor6252
@obinnaokafor6252 Жыл бұрын
He does not use f#
@raphaelbatel
@raphaelbatel Жыл бұрын
The Result type in langauge-ext says /// `Result` (and `OptionalResult`) is purely there to represent a concrete result value of a invoked lazy operation /// (like `Try`). You're not really meant to consume it directly. Any comment on the "You're not really meant to consume it directly." part?
@crazyst3ve01
@crazyst3ve01 Жыл бұрын
Great video. I would only add that this is not a `concept in C#` but a concept in most current languages (especially ones with union types), and is a concept in development and monads as a whole. C# is missing it, and it's up to developers to crudely create it in C#. I know it's mentioned later, but missing Union types and monads is a sore point for me with C# It's important for developers to look outside of their eco-system and know what is missing or neat in other ecosystems. Or even better know what doesn't exist outside your ecosystem, and why your ecosystem is 'better' for a given task/solution.
@iuribrindeiro5009
@iuribrindeiro5009 Жыл бұрын
Yep! It is wildly used in functional languages, and as Mads Torgersen said: "OO is kind of screwed... it was not designed for the cloud". -> kzbin.info/www/bejne/eX2ui2qQnLucmtE
@obinnaokafor6252
@obinnaokafor6252 Жыл бұрын
@@iuribrindeiro5009 DO you know that there is something called industry standard languages and growing languages? And toy languages?
@iuribrindeiro5009
@iuribrindeiro5009 Жыл бұрын
@@obinnaokafor6252 I'm not sure what do you mean by "toy languages" but I think I do understand related to the other 2. Functional is not a language but a paradigm created on early 30s, if that is where u are going with. Don't get mad, I'm just replicating what the C# lead designer said :)
@user-tk2jy8xr8b
@user-tk2jy8xr8b Жыл бұрын
> can only be one of the two values Partially true, there are Success and Faulted states. However, default(Result) will have State=Faulted and throw "bottom exception" on accessing the Exception prop. This approach is similar to what they have there in Either, but Either has the "Bottom" state explicitly (I won't stop arguing that the "bottom" state makes no sense in an eager language and it's a poor translation from Haskell). Actually you can see IsBottom in the intellisense list at 9:32
@xanhxanh5097
@xanhxanh5097 8 ай бұрын
Nick in the end you mention to link the fluent result package. but its not in the description.
@peterriesz69
@peterriesz69 9 ай бұрын
I have always prefered the action's return type match to match the model. This enables ApiExplorer to produce documentation to match the method definition instead of having to annotate with ProducesResponseType which just feels like redundant boilerplate that is also open to error. Does anyone know a solution to this or are we just forced to return IActionResult when using result objects?
@winchester2581
@winchester2581 Жыл бұрын
I'm writing my bachelor work about Minimal API (it was heavily inspired by you, Nick!), and in my work I used this approach via ardalis/Result. It's quite a useful library, I love it, you can even translate your result to minimal API response. It has less of control, but it's simple. Perhaps, I'll write my own implementation because I want to return conventional results for scenarios like 400, 404 etc.
@brtk7
@brtk7 Жыл бұрын
😳 sorry but how can you write thesis about minimal api, what is scientific about it? It’s just way of organizing you endpoint, who cares if it’s based on mvc , or any other concept, it’s point is to allow hit you http server and get desired resource based on ‘path’(http request) Back to the video, This concept of result monads is only a way of flow control that language like rust, functional supports and c# tries to mimic. It’s great but it’s will hard to add native support because all standard libraries should have been rewritten to not throw the exception but rather expose it as a monad, and some api would also has to change. Basically even string parse would need to be rewrites to plainly admit that hey you can get an string or errorX and when you get error do something with it, or at least panic ;) it’s embarrassing that so many people are overwhelmed and treat it like a genius revolution, but it shows how advanced programmers are these days 😢😂 And of course I would love to have it in c# and I am trying to adopt it as much as I can in my application code. Maybe eventually even some libraries starts to be based on that idea and c# devs teams figure somehow how to add support with maintaining the backward compatibility 🎉😃
@winchester2581
@winchester2581 Жыл бұрын
@@brtk7 well, we don't have overwhelming requirements for our workaround, so I picked this topic for some sort of experiments. Yes, you can say that it's just a technique for API structuring, but as Nick mentioned it can give you the possibility to build a new approach So it can be something that simple. Other people in our university literally picked up topics like Spring Boot WebFlux or just CRUD applications
@brtk7
@brtk7 Жыл бұрын
@@winchester2581 you could instead build your own custom middleware on top on asp and invent, research new way of building api, that would have better way of defining these endpoints or even get rid of asp and incorporate simple http library or use standard code primitives like httpListener. And that would add value to your project and present you more like a researcher rather than a technical noob getting existing with technology that doesn’t completely understand. Sorry for that, but If I were to appreciate such projects, I would insult people who truly strive and put effort into their thesis work. 🥲😁
@mhDuke
@mhDuke 6 ай бұрын
did you guys notice where this leads to? I been playing with the same concept of a Result type such that programmer cannot access the value directly, only call Match(onSucessDelegate, onFailureDelegate), but then this quickly turned all my code into a function calling another function calling another function passing the result of each operation to the next! I am starting to see the concept of functional programming but man this is totally outside comfort zone!
@rafaeldericksanchezlockwar4920
@rafaeldericksanchezlockwar4920 Жыл бұрын
Great video nick! We've been using this approach lately but the implicit operator part really blow my mind. Also would be good to see a video of the Language Extention package👌👌
@proosee
@proosee Жыл бұрын
What was always bugging me about this approach was lack of discriminated unions in C# which force you to create some artificial interfaces (or separate class + additional code for one type to another) just to be able to return multiple types of failures (e.g. method is calling two other methods which return different types of failures). Not only such interface is artificial, it also binds two different parts of code in a way that might be distant from each other in your codebase. Of course, someone can argue that exceptions actually all derive from one class so you can do the same with failures, but that's a stretch to my taste.
@tarikpalic6304
@tarikpalic6304 Жыл бұрын
Man, I just got used to working with OneOf library, and now you come up with this :D
@ershadnozari
@ershadnozari Жыл бұрын
Brilliant, thanks!
@andrewstevens7764
@andrewstevens7764 Жыл бұрын
In the context of a web Api, When would you not wrap an exception in a result? Would it just be when you dont want to share the error details with the user as it's not something that could help them? Eg an IOException or something like that
@crazyfox55
@crazyfox55 Жыл бұрын
Suppose I tried to create a movie that is already in the database what should the movie service do? Is the movie validator responsible for checking if the movie already exists? I would think the movie validator is purely the movie itself such as title can't be more than 50 characters. Now the movie year is also tricky because it relies on another "time" service should that really be in the movie validator? What do you think of adding another validator that handles time requirements? As well as a movie validator for the repository? Where would you draw the line? Does each dependency on a service deserve its own movie validator? Maybe I need a movie validator factory which will build a composite of movie validators depending on how much I want to validate. For the create case I would want to validate static properties like the movie title, time based properties like the year, and uniqueness properties like the Id. What do you think?
@marna_li
@marna_li Жыл бұрын
I tried to implement my own Result and Option types based on Beef lang's version which is based on its enum type. Works pretty much the same as in Rust - but C#-ish. The problem obviously is that C# doesn't have the feature yet. The code gets more verbose. And in my implementation there is a problem with the generic arguments not being inferred.
@dejansavanovic4476
@dejansavanovic4476 11 ай бұрын
Hey @NickChapsas what do you think about always returning same object for every API, something like Response object which has properties data, errors, code,..., and if code has failed it will return this object whit errors property inserted or if it is sussecful it will return data property inserted, what do you think about handling in this way? And I saw you used exception throwing as way of validation, isn't maybe this way too expensive for validation of data?
@allinvanguard
@allinvanguard Жыл бұрын
I wish this would make it to the BCL instead of having to import e.g. LanguageExt. C#8's nullability already is a great Optional compatibility option out of the box. Judging by how functional C# is getting, this is probably just a matter of time before we have functional constructs in the BCL.
@crazyst3ve01
@crazyst3ve01 Жыл бұрын
Option is not the same as nullable. You can wrap it, but it is different.
@allinvanguard
@allinvanguard Жыл бұрын
@@crazyst3ve01 Sure, it's not the same, but the semantics are similar enough for most use cases
@TheCarstenSuurland
@TheCarstenSuurland Жыл бұрын
I'm using it with ROP (Railway) and I love it. I'm currently trying to create "fluent ROP" that supports async operations - which is not easy... I would love for you to take a crack at it. Would be interesting to see. For instance : var result = await someOperation(parameter).OnSuccess(x => x...).OnFailure(x => x...);
@fishzebra
@fishzebra Жыл бұрын
Am very interested in Maybe and Either like used in Language Extns, although have found it hard to convince others, would be good to raise the knowledge of these basic functional approaches.
@MrBleachFix
@MrBleachFix Жыл бұрын
Aye I’ve helped create an enterprise system from the ground up using LanguageExt. It’s a bit rubbish switching between that and OO or procedural so stick with a pattern if it suits your case
@Ankh.of.Gaming
@Ankh.of.Gaming Жыл бұрын
I find myself using this very often in C# ever since I started learning Rust. Go figure.
@Kantragor
@Kantragor 9 ай бұрын
Personally, I prefer to throw custom exception that could be catched later on in the code. Having result type making lots of methods looking cumbersome and given that generics makes your redability worse with the time, one can also privilege just simple .net exceptions
@ryan-heath
@ryan-heath Жыл бұрын
It’s like async when you start using it you will almost always need to alter the call chain as well, or you will shallow errors. That’s said, I only see value in this when doing validation and (sometimes) calling an external component. In other case just let the exceptions flow to the upper level.
@guybahar6856
@guybahar6856 Жыл бұрын
Hi Nick, What is the different from the package OneOf ?
@soonts
@soonts 10 ай бұрын
Based on the prototype, the ValidateAsync method does some IO like networking, otherwise it wouldn't be async. With your FP shenanigans, you now have 3 possible outcomes: success, validation error, or exception due to failed IO. This means you have to handle 3 cases otherwise you'll introduce bugs. For this reason, I usually throw exceptions for validation errors. They simplify code at call sites, also improves readability. In the rare cases when performance cost of exceptions matters, I usually do something like `bool tryDoSomething(out R result);`
@_Aarius_
@_Aarius_ Жыл бұрын
I wish c# had value-holding enums like rust does. Rusts Result enum that holds Ok(value) and Err(error), aswell as the similar option some/none are super useful, and Result is a super commonly used thing there (because it has no exceptions in the language)
@uladzimirmalhin2379
@uladzimirmalhin2379 Жыл бұрын
This approach reminds me of a OneOf package that you've used in one of your videos, which in my opinion is more flexible. Using OneOf, you can specify multiple positive results, multiple errors and match all of them, so that you don't just return BadRequest when there is an error. Instead you can use more appropriate status codes for each error type. Do you think Result type has any advantages over it?
@adrian_franczak
@adrian_franczak Жыл бұрын
if you use for error something like rust enums you don't need extra parameters
@alex22932
@alex22932 Жыл бұрын
I started using OneOf after Nick showed it in a video a couple months back. I was wondering why would you use a Result class instead of OneOf. It seems like OneOf would be more flexible.
@AnonymousDeveloper1
@AnonymousDeveloper1 Жыл бұрын
Looks like it's functional programming stuff. Too bad I don't know it yet but it seems to be very powerful. Good video as usual.
@gaxkiller
@gaxkiller Ай бұрын
I think it is important not to use abbreviations in lambda when using those new concepts. I am pretty familiar with the result / either type but I always name the lambda param when matching with full name. I think "movie" instead of "m" might help people understand: "ah ok that is where I can access my value". Of course people can see the type of the lambda param but still I think making it easier for new people is never bad :)
@scott98390
@scott98390 Жыл бұрын
First time I've seen the PureAttribute - can you go into detail on that?
@peculiar-coding-endeavours
@peculiar-coding-endeavours Жыл бұрын
Used this approach for years. Away with throwing exceptions and ending up in nondeterministic control flows. The little bit of added verbosity is a small price to pay for cleaner and predictable flow.
@MrSaydo17
@MrSaydo17 Жыл бұрын
Been using Result for 5+ years. I can't live without it.
@orterves
@orterves Жыл бұрын
If you're at all confused just remember - a monad is just a monoid in the category of endofunctors. What's the problem? (*Please* can C# get sum types as a core feature. They've already stolen pretty much everything else good from F#. Though currying and computation expressions would sure be nice too...)
@luiscamacho1917
@luiscamacho1917 10 ай бұрын
In my project we use a custom result type with the flag Is success , and Result = object target but I will propose the library that you success to avoid have the lots of if, thanks
@ethanshoham2855
@ethanshoham2855 Жыл бұрын
How do you think exception handling from external resources should be? for example mongo driver/sql/external sdk clients and HttpClient they all use the exceptions patter. Should I Try-Catch all outer resources in a wrapper class that returns Result?
@PelFox
@PelFox Жыл бұрын
Interesting question. A lot of SDKs do use exceptions for things like 404, 409 and 429.
@JexsGG
@JexsGG Жыл бұрын
Which approach do you generally prefer when comparing this Result type approach to something like the OneOf library that you demonstrated in the "How to use Discriminated Unions Today in C#" video from a few months back?
@nickchapsas
@nickchapsas Жыл бұрын
I use both. I use OneOf generally and I have a result type through oneof
@TheNorthRemember
@TheNorthRemember 4 ай бұрын
5:19 where are those vids you talked about exception flow control
@nikamamniashvili8633
@nikamamniashvili8633 Жыл бұрын
please make more videos on functional programing principes in c#
@nocgod
@nocgod Жыл бұрын
if you add a "public object Value => IsSuccess ? _value : _error" would allow you to use native switch expression, res.Value switch { TValue v => do your thing, TError e => do your other thing } In addition, LanguageExt is a bit old and doesn't work well with AOT compilation and stuff like that, be careful
@RobinHood70
@RobinHood70 Жыл бұрын
True, but you'll probably lose a lot of performance with the boxing. If that's not important in your use case, then by all means, go for it.
@nooftube2541
@nooftube2541 Жыл бұрын
@@RobinHood70 not a lot in most cases. Plus usually it used for classes, so everything already boxed.
@nocgod
@nocgod Жыл бұрын
@@RobinHood70 you might pay some price. Easily testable with benchmarkDotNet:)
@user-vk5ww8wd8b
@user-vk5ww8wd8b 5 ай бұрын
I have a project that uses exceptions for control flow and have been thinking about porting it to use this Results approach, but i have one issue with this: The MovieService is triggering validation and checking. I dont think i want to have that code in every single service. Normally with exceptions you have something that triggers that automatically, so i'm wondering how something like mediator (the pattern) behaviors could be used to automate this and how that code would look like.
@BillieJoe512
@BillieJoe512 Жыл бұрын
I am a big fan of result types, but not of the Match(), IfSuccess(), etc methods. I don't like that they implement the same behaviour as the native language constructs without using them. this can be confusing to junior programmers and I imagine it does not pair well with code flow analysis and other tools. I'm trying to write roslyn analyzers to force - or remind - the dev to check a result's state before using its value (as does @DiadeTedio Tedio)
@user-ft8bd7tx3e
@user-ft8bd7tx3e 3 ай бұрын
if there possibilty multile error then how should hangle in Api Controller?
@OrgesKreka
@OrgesKreka Жыл бұрын
Looking forward for the LanguageExt video.
@notarobot22
@notarobot22 Жыл бұрын
This seems like an interesting approach. I'm just a bit concerned that valuable stack trace information may get lost when handling errors this way?
@mathewpowell-davis4545
@mathewpowell-davis4545 11 ай бұрын
Would you use the same object to pass around database exceptions?
@mtsmithtube
@mtsmithtube 11 ай бұрын
What if your repository throws an exception? It looks like it would bubble up to your controller which no longer has a try/catch?
@diadetediotedio6918
@diadetediotedio6918 Жыл бұрын
I'm making my own Result type with a roslyn analyzer that would enforce error checking, I think it's the next step on this game (it is also a struct so no heap allocations for results are needed)
@BillieJoe512
@BillieJoe512 Жыл бұрын
I'm working on exactly the same 😂 very interesting to dive into the roslyn analyzers
@diadetediotedio6918
@diadetediotedio6918 Жыл бұрын
​@@BillieJoe512 It's very fun (not every time hahahahaha) to work with them, I kinda like the whole roslyn thing. If they made roslyn source generators to be able to modify the source code I would do something like function inlines for those .Match functions over result types, but until this occurs I work with the available tools
@pingu2k4
@pingu2k4 Жыл бұрын
I've been using a (inferior) result type similar to this for ages... Didn't realise it was a common thing tbh. Funny how people end up at similar destinations with things like this... I remember many years ago my astonishment that ORM's were a thing, having been struggling with my own implementation hah.
@creamyhorror
@creamyhorror Жыл бұрын
Oh, I've been returning (Result, Value) tuples from functions instead of creating a full struct like this. It just seems simpler. Also my Results are sometimes custom Enums instead of Booleans, in order to indicate the exact result code / reason for failure - e.g. for a PlaceOrder() function, a Result might be PlaceOrderResult.Success, PlaceOrderResult.InsufficientFunds, or PlaceOrderResult.OutOfStock. This lets me handle specific cases (without using Exceptions, which I reserve for real or uncommon errors). I'll have to consider a struct-based approach instead. Too bad C# doesn't have sum types / discriminated unions, forcing us to use methods like this, or Option/Variant/AnyOf types, or passing in reference arguments to receive output values.
@NoName-1337
@NoName-1337 Жыл бұрын
What is the best practice for Result and Option in combination (e.g. db query situation)? Should I use it in some sort Result (or Async Task)? But then I need to return always Option.Some or OptionNone, because it can't be implicitly converted. Is there a better way? Nullable Types such as T? works differently with Match(), why? Why Result has no implicit error convert function? AND the documentation of LanguageExt is very poor. I like this concept, but the implementation is very poor in my opinion.
@dovh49
@dovh49 Жыл бұрын
The big mistake people make about this pattern is that they view the result type as either success or an error. When it is really returning an accept type or an out-of-band message that halts normal execution. Viewing it like that you can use it for more use cases and make the return very simple. Also, using monads makes it nicer. But most people have a hard time grokking that so at work I go with simple rather than easy (for me).
@hanspetervollhorst1
@hanspetervollhorst1 Жыл бұрын
And now use IPipelineBehaviour to return a ValidationFailed, if validation fails, next() otherwise. I gave up on that and moved the Validation into my IResultHandler, which is suboptimal, so say the least
@ChristopherWodarczyk-hg6jm
@ChristopherWodarczyk-hg6jm 9 ай бұрын
While I do really like this idea and I have experimented with it on and off several times, something makes me skittish about propagating its usage everywhere. This may be an incorrect and unfair comparison (correct me if wrong). but when I have used it, I have found it needs to be used from lowest layer all the way back to the controller consistently, as you would an async/await Task pattern. But using it all the way from data layer back to controller, I cannot see avoiding the use of many captures, which does worry me about using it too much through the code-base. While some may argue that the same can happen with LINQ lambdas, usually your LINQ lambdas are not extraordinarily complex, just simple predicates/mapping methods. The logic you need inside of some of these functional lambdas can get quite complex and lead to captures. Of course, I could have just been using this wrong all along, and I hate to ever say a pattern is bad when it has a such a cool potential, but I guess for whatever reason I can't be sold 100%.... yet. And then I have to also wonder why the C# committee hasn't ever adopted this officially even though it's been around for a while now. It does make me wonder if there are some things that don't work with the language constructs 100% without some side-effects.
@user-nw7jo5xw9x
@user-nw7jo5xw9x Жыл бұрын
if i'm not mistaken, it is the rust way to return error or result
@user-fr7nn1yq3m
@user-fr7nn1yq3m Ай бұрын
I still think we need some kind of global try/catch setup, because exceptions are like uninvited guests-they can show up anywhere. Predicting every single place an app might throw an error just isn't doable. So, it makes me wonder, why go through the hassle of wrapping everything in a Result and making our codebase heftier? Here's a scenario: suppose you have a method that's been smooth sailing, no exceptions, so you didn't wrap it in a Result. But then, during development, something changes, and now it might throw an error. This means potentially updating a lot of code that calls this method, even when there might not be a strong reason for it. Typically, a standard approach with middleware could handle this situation without forcing any major changes elsewhere. Seeing as we're already using Task, adding more wrappers into the mix feels like we're going overboard. If we keep this up, our type definitions are going to get so bloated, not even a UWQHD screen could display them all. 🙂
@user-qi7mk6be7u
@user-qi7mk6be7u Ай бұрын
Did the same thing actually by using objectresult class . the happy path was returning the actual object . the error path was the objectresult with the error and the code inside . same things
@user-ft8bd7tx3e
@user-ft8bd7tx3e 3 ай бұрын
why did not return strong type in api? if it is, then what should be code structure in API?
@MistyKu
@MistyKu Жыл бұрын
I think it is much harder to maintain than typical exception/middleware handling flow. There is nothing stopping a developer to not use Match and forget to handle wrong scenario. Also you need to remember to call MapToResponse otherwise you'd get completely different error DTO. And the thing which I don't like the most - if you have service A calling service B calling service C you'd need to return Result all the way back from service C to service A.
@neociber24
@neociber24 Жыл бұрын
If they ever stabilize the new enum types this will be even better
@luki215PL
@luki215PL Жыл бұрын
It's great, but in c# we have EXCEPTIONS. If you want to use that, go to rust for example. This is my option. Why to use that if we have to handle some exceptions in third part library. It's not build in language
@nickchapsas
@nickchapsas Жыл бұрын
This is coming natively in C# as a feature as well
@maybe4900
@maybe4900 11 ай бұрын
Oh boy, even haskell have EXCEPTIONS, even rust have panic. It's about how do you wrap your exceptions. You can wrap your httpClient calls with Either monad, you can wrap your db calls with Either etc.., but other parts of code should be pure and don't get divergence.
@Piotryczko-Jedi
@Piotryczko-Jedi Жыл бұрын
Hi Nick, around 5:10 you're talking about links to videos about "exceptions as control flow which is bad way", but I can't find the links. Please tell me how to find it.
@nickchapsas
@nickchapsas Жыл бұрын
kzbin.info/www/bejne/l2LclmybfLl1b5o
@Piotryczko-Jedi
@Piotryczko-Jedi Жыл бұрын
​@@nickchapsas thanks 😉
@ianknowles
@ianknowles Жыл бұрын
Glad to see people advocating for this pattern but this is why I moved to Rust!
Getting Started with Event Sourcing in .NET
37:07
Nick Chapsas
Рет қаралды 19 М.
How to use Discriminated Unions Today in C#
17:09
Nick Chapsas
Рет қаралды 58 М.
where is the ball to play this?😳⚽
00:13
LOL
Рет қаралды 14 МЛН
Не пей газировку у мамы в машине
00:28
Даша Боровик
Рет қаралды 9 МЛН
格斗裁判暴力执法!#fighting #shorts
00:15
武林之巅
Рет қаралды 48 МЛН
3 .NET "Best Practices" I Changed My Mind About
10:16
Nick Chapsas
Рет қаралды 98 М.
Why Startups Hate .NET and C#
10:38
Nick Chapsas
Рет қаралды 239 М.
The 3 Biggest Mistakes of Object Mapping in .NET
11:33
Nick Chapsas
Рет қаралды 62 М.
The best Nuget package you’ve never heard of
16:32
Nick Chapsas
Рет қаралды 114 М.
Swagger is Going Away in .NET 9!
10:48
Nick Chapsas
Рет қаралды 62 М.
What are Interfaces? (C# Basics)
13:54
Code Monkey
Рет қаралды 199 М.
Should you stop returning "null"? | Functional C#
11:32
Nick Chapsas
Рет қаралды 104 М.
where is the ball to play this?😳⚽
00:13
LOL
Рет қаралды 14 МЛН