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

Sdílet
Vložit
  • čas přidán 21. 05. 2023
  • 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

Komentáře • 257

  • @nmacw93
    @nmacw93 Před 11 měsíci +29

    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 Před 11 měsíci +34

    Definitely cover more functional stuff! This kind of content is exactly what we love to see, practical application of functional concepts.

  • @SifSehwan
    @SifSehwan Před 11 měsíci +72

    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 Před 11 měsíci +6

      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 Před 11 měsíci +11

      Today is the first time I've heard of "railway pattern", why does this make so much sense.

    • @dolgan12
      @dolgan12 Před 11 měsíci +14

      Welcome to F# :)

    • @SifSehwan
      @SifSehwan Před 11 měsíci

      @@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 Před 29 dny

      @@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).

  • @umairbutt1355
    @umairbutt1355 Před 11 měsíci +21

    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!

  • @CecilPhillip
    @CecilPhillip Před 11 měsíci +4

    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 😂

  • @parlor3115
    @parlor3115 Před 11 měsíci +13

    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).

  • @brianviktor8212
    @brianviktor8212 Před 11 měsíci

    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.

  • @MetalKid007
    @MetalKid007 Před 11 měsíci +23

    I've used this sort if pattern for over 10 years and it has never let me down! :)

    • @iuribrindeiro5009
      @iuribrindeiro5009 Před 11 měsíci +3

      This is probably a better introductory video: czcams.com/video/US8QG9I1XW0/video.html

  • @DryBones111
    @DryBones111 Před 11 měsíci +2

    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.

  • @mindaugasw
    @mindaugasw Před 11 měsíci +4

    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 Před 8 měsíci

      Agreed.

    • @softcodeacademy
      @softcodeacademy Před měsícem +1

      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.

  • @gveresUW
    @gveresUW Před 10 měsíci +1

    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.

  • @cjamesrohan
    @cjamesrohan Před 11 měsíci +3

    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!

  • @scottroberts7693
    @scottroberts7693 Před 11 měsíci +13

    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 Před 11 měsíci +2

      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 Před 11 měsíci

      @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 Před 11 měsíci +20

    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.

  • @michaelrall8142
    @michaelrall8142 Před 5 měsíci +1

    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.

  • @glennstartin8575
    @glennstartin8575 Před 11 měsíci

    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.

  • @mzeeshan
    @mzeeshan Před 11 měsíci

    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.

  • @andyfitz1992
    @andyfitz1992 Před 10 měsíci

    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.

  • @DrHeinzDoofenshmirtz
    @DrHeinzDoofenshmirtz Před 11 měsíci

    I have jumped on this Flow Control as well with the ErrorOr library which is awesome! It supports returning multiple errors as well.

  • @anreton
    @anreton Před 11 měsíci +2

    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 Před 11 měsíci +6

    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 Před 11 měsíci

      Lol same. I was also watching his same video and actually looking if he had a video on Results.

  • @Danny1986il
    @Danny1986il Před 11 měsíci +1

    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.

  • @twiksify
    @twiksify Před 10 měsíci

    Have a peek at rust Option and Result for some other useful extensions which are quite simple to implement yourself.

  • @HartzFEAR444
    @HartzFEAR444 Před 11 měsíci +8

    5:16 "I'm gonna link them in the description below" - you forgot :(

  • @saffronomicon
    @saffronomicon Před 7 měsíci

    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.

  • @MrNachosVIDEOS
    @MrNachosVIDEOS Před 11 měsíci +16

    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 Před 11 měsíci

      But isn't that the purpose of nullable types?

    • @MrNachosVIDEOS
      @MrNachosVIDEOS Před 11 měsíci +1

      @@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

  • @Aralmo640
    @Aralmo640 Před 11 měsíci

    I do love the result approach, specially when coupled with linq syntax to avoid the nasty nesting it usually creates.

  • @damiantedrow3218
    @damiantedrow3218 Před 11 měsíci

    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.

  • @dcuccia
    @dcuccia Před 11 měsíci

    Great video, thanks. Look forward to a day where we can use switch expressions with DU deconstruction.

  • @user-km7fd2le8f
    @user-km7fd2le8f Před 11 měsíci

    Yes, I'd love a video about functional concepts like Some, None, Unit, etc.

  • @fsharpfan
    @fsharpfan Před 10 měsíci +6

    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 Před 10 měsíci +4

      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 Před 4 měsíci

      @@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.

  • @iuribrindeiro5009
    @iuribrindeiro5009 Před 11 měsíci +10

    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.

  • @dcuccia
    @dcuccia Před 11 měsíci

    Yes! More functional discussions, please!!

  • @nooftube2541
    @nooftube2541 Před 11 měsíci

    Also you can use Try...(out result) patter. You can also add out failure to signature if you need.

  • @crazyst3ve01
    @crazyst3ve01 Před 11 měsíci +10

    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 Před 11 měsíci

      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". -> czcams.com/video/CLKZ7ZgVido/video.html

    • @obinnaokafor6252
      @obinnaokafor6252 Před 11 měsíci

      @@iuribrindeiro5009 DO you know that there is something called industry standard languages and growing languages? And toy languages?

    • @iuribrindeiro5009
      @iuribrindeiro5009 Před 11 měsíci

      @@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 :)

  • @jamienordmeyer4345
    @jamienordmeyer4345 Před 11 měsíci +1

    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 Před 11 měsíci

      hello, could you please give me the link to the code about this idea (converting object result to IActionResult)

    • @jamienordmeyer4345
      @jamienordmeyer4345 Před 11 měsíci +1

      @@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. :)

  • @timschwallie1589
    @timschwallie1589 Před 11 měsíci

    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.

  • @winchester2581
    @winchester2581 Před 11 měsíci

    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 Před 11 měsíci

      😳 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 Před 11 měsíci

      @@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 Před 11 měsíci

      @@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. 🥲😁

  • @marna_li
    @marna_li Před 11 měsíci +1

    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.

  • @mhDuke
    @mhDuke Před 6 měsíci

    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!

  • @Kantragor
    @Kantragor Před 9 měsíci +1

    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

  • @fishzebra
    @fishzebra Před 11 měsíci

    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.

  • @xanhxanh5097
    @xanhxanh5097 Před 8 měsíci

    Nick in the end you mention to link the fluent result package. but its not in the description.

  • @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👌👌

  • @gaxkiller
    @gaxkiller Před měsícem

    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 :)

  • @proosee
    @proosee Před 11 měsíci +1

    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.

  • @user-fr7nn1yq3m
    @user-fr7nn1yq3m Před měsícem

    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. 🙂

  • @peterriesz69
    @peterriesz69 Před 9 měsíci

    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?

  • @user-tk2jy8xr8b
    @user-tk2jy8xr8b Před 11 měsíci

    > 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

  • @_Aarius_
    @_Aarius_ Před 11 měsíci +1

    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)

  • @MrBleachFix
    @MrBleachFix Před 11 měsíci +1

    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

  • @Mazzphysics
    @Mazzphysics Před 11 měsíci

    I will def try it in my own projects.

  • @tarikpalic6304
    @tarikpalic6304 Před 11 měsíci

    Man, I just got used to working with OneOf library, and now you come up with this :D

  • @TheCarstenSuurland
    @TheCarstenSuurland Před 11 měsíci

    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...);

  • @uladzimirmalhin2379
    @uladzimirmalhin2379 Před 11 měsíci +10

    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 Před 11 měsíci

      if you use for error something like rust enums you don't need extra parameters

    • @alex22932
      @alex22932 Před 11 měsíci +2

      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.

  • @nooftube2541
    @nooftube2541 Před 11 měsíci +11

    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 Před 11 měsíci +6

      If it succs then it is okay 😅

  • @raphaelbatel
    @raphaelbatel Před 11 měsíci +1

    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?

  • @soonts
    @soonts Před 9 měsíci

    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);`

  • @nikamamniashvili8633
    @nikamamniashvili8633 Před 11 měsíci +1

    please make more videos on functional programing principes in c#

  • @allinvanguard
    @allinvanguard Před 11 měsíci +1

    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 Před 11 měsíci

      Option is not the same as nullable. You can wrap it, but it is different.

    • @allinvanguard
      @allinvanguard Před 11 měsíci

      @@crazyst3ve01 Sure, it's not the same, but the semantics are similar enough for most use cases

  • @pingu2k4
    @pingu2k4 Před 11 měsíci

    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.

  • @ershadnozari
    @ershadnozari Před 11 měsíci

    Brilliant, thanks!

  • @Ankh.of.Gaming
    @Ankh.of.Gaming Před 11 měsíci +4

    I find myself using this very often in C# ever since I started learning Rust. Go figure.

  • @ChristopherWodarczyk-hg6jm
    @ChristopherWodarczyk-hg6jm Před 9 měsíci

    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.

  • @crazyfox55
    @crazyfox55 Před 11 měsíci

    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?

  • @orterves
    @orterves Před 11 měsíci +4

    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...)

  • @AnonymousDeveloper1
    @AnonymousDeveloper1 Před 11 měsíci

    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.

  • @ryan-heath
    @ryan-heath Před 11 měsíci +4

    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.

  • @nathancurnow2410
    @nathancurnow2410 Před 11 měsíci

    I really like that you pretty much just reimplemented the Rustlang Result enum. Great work!

  • @TheNorthRemember
    @TheNorthRemember Před 4 měsíci +1

    5:19 where are those vids you talked about exception flow control

  • @scott98390
    @scott98390 Před 11 měsíci +2

    First time I've seen the PureAttribute - can you go into detail on that?

  • @peculiar-coding-endeavours
    @peculiar-coding-endeavours Před 11 měsíci

    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.

  • @andrewstevens7764
    @andrewstevens7764 Před 11 měsíci

    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

  • @MrSaydo17
    @MrSaydo17 Před 11 měsíci

    Been using Result for 5+ years. I can't live without it.

  • @ethanshoham2855
    @ethanshoham2855 Před 11 měsíci +3

    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 Před 11 měsíci

      Interesting question. A lot of SDKs do use exceptions for things like 404, 409 and 429.

  • @diadetediotedio6918
    @diadetediotedio6918 Před 11 měsíci +1

    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 Před 11 měsíci

      I'm working on exactly the same 😂 very interesting to dive into the roslyn analyzers

    • @diadetediotedio6918
      @diadetediotedio6918 Před 11 měsíci +1

      ​@@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

  • @nocgod
    @nocgod Před 11 měsíci +1

    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 Před 11 měsíci

      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 Před 11 měsíci

      @@RobinHood70 not a lot in most cases. Plus usually it used for classes, so everything already boxed.

    • @nocgod
      @nocgod Před 11 měsíci

      @@RobinHood70 you might pay some price. Easily testable with benchmarkDotNet:)

  • @JexsGG
    @JexsGG Před 11 měsíci +1

    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  Před 11 měsíci +3

      I use both. I use OneOf generally and I have a result type through oneof

  • @dejansavanovic4476
    @dejansavanovic4476 Před 11 měsíci

    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?

  • @luiscamacho1917
    @luiscamacho1917 Před 9 měsíci

    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

  • @notarobot22
    @notarobot22 Před 11 měsíci

    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?

  • @IcaroFelix2023
    @IcaroFelix2023 Před 11 měsíci

    It reminds me a structure of an Observable from rxjs with two callbacks.

  • @user-nw7jo5xw9x
    @user-nw7jo5xw9x Před 11 měsíci

    if i'm not mistaken, it is the rust way to return error or result

  • @user-vk5ww8wd8b
    @user-vk5ww8wd8b Před 5 měsíci

    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.

  • @guybahar6856
    @guybahar6856 Před 11 měsíci +1

    Hi Nick,
    What is the different from the package OneOf ?

  • @user-qi7mk6be7u
    @user-qi7mk6be7u Před měsícem

    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

  • @OrgesKreka
    @OrgesKreka Před 11 měsíci +1

    Looking forward for the LanguageExt video.

  • @BillieJoe512
    @BillieJoe512 Před 11 měsíci +2

    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)

  • @dovh49
    @dovh49 Před 11 měsíci

    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 Před 11 měsíci

    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

  • @mtsmithtube
    @mtsmithtube Před 11 měsíci +1

    What if your repository throws an exception? It looks like it would bubble up to your controller which no longer has a try/catch?

  • @vencislavvidov
    @vencislavvidov Před 11 měsíci

    it will be nice to make more videos on LangugeExt:)

  • @ScottBarnesBass
    @ScottBarnesBass Před 11 měsíci

    Can someone point me to the video explaining why we shouldn’t use exceptions for control flow as mentioned. I keep having to have this conversation with one of my devs…. 😊

  • @neociber24
    @neociber24 Před 11 měsíci

    If they ever stabilize the new enum types this will be even better

  • @creamyhorror
    @creamyhorror Před 11 měsíci +1

    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.

  • @Piotryczko-Jedi
    @Piotryczko-Jedi Před 11 měsíci

    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.

  • @user-ft8bd7tx3e
    @user-ft8bd7tx3e Před 2 měsíci

    if there possibilty multile error then how should hangle in Api Controller?

  • @TheTortillaCurtain
    @TheTortillaCurtain Před 11 měsíci

    Any more information about LanguageExt is always welcome.

  • @R0ckyRocket
    @R0ckyRocket Před 11 měsíci

    Really nice video

  • @trispens
    @trispens Před 11 měsíci

    Looks great, but i am a bit worried about the impact on the performance, will all of the health checks be triggered on every request that goes into the service ? Or will it perform the checks every x seconds?

    • @nickchapsas
      @nickchapsas  Před 11 měsíci +1

      Services are usually automated to call health checks every few seconds