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

แชร์
ฝัง
  • เผยแพร่เมื่อ 13 ต.ค. 2024

ความคิดเห็น • 264

  • @nmacw93
    @nmacw93 ปีที่แล้ว +32

    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.

  • @SifSehwan
    @SifSehwan ปีที่แล้ว +76

    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 ปีที่แล้ว +7

      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 ปีที่แล้ว +12

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

    • @dolgan12
      @dolgan12 ปีที่แล้ว +14

      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 6 หลายเดือนก่อน +2

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

  • @EEEdoman
    @EEEdoman ปีที่แล้ว +37

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

  • @MetalKid007
    @MetalKid007 ปีที่แล้ว +25

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

    • @iuribrindeiro5009
      @iuribrindeiro5009 ปีที่แล้ว +3

      This is probably a better introductory video: th-cam.com/video/US8QG9I1XW0/w-d-xo.html

  • @scottroberts7693
    @scottroberts7693 ปีที่แล้ว +15

    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 ปีที่แล้ว +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 ปีที่แล้ว

      @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

  • @gveresUW
    @gveresUW ปีที่แล้ว +2

    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.

  • @shelbytimbrook2095
    @shelbytimbrook2095 ปีที่แล้ว +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.

    • @SalmanShafiq-y3q
      @SalmanShafiq-y3q 8 หลายเดือนก่อน

      would u plz share ur ApiResult class?

  • @CecilPhillip
    @CecilPhillip ปีที่แล้ว +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 😂

  • @al-doori2392
    @al-doori2392 ปีที่แล้ว +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 ปีที่แล้ว

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

  • @twiksify
    @twiksify ปีที่แล้ว

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

  • @MrNachosVIDEOS
    @MrNachosVIDEOS ปีที่แล้ว +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 ปีที่แล้ว

      But isn't that the purpose of nullable types?

    • @MrNachosVIDEOS
      @MrNachosVIDEOS ปีที่แล้ว +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

  • @fsharpfan
    @fsharpfan ปีที่แล้ว +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 ปีที่แล้ว +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 9 หลายเดือนก่อน

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

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

  • @brianviktor8212
    @brianviktor8212 ปีที่แล้ว

    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.

  • @andyfitz1992
    @andyfitz1992 ปีที่แล้ว

    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.

  • @parlor3115
    @parlor3115 ปีที่แล้ว +14

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

  • @jamienordmeyer4345
    @jamienordmeyer4345 ปีที่แล้ว +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 ปีที่แล้ว

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

    • @jamienordmeyer4345
      @jamienordmeyer4345 ปีที่แล้ว +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. :)

  • @DryBones111
    @DryBones111 ปีที่แล้ว +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.

  • @michaelrall8142
    @michaelrall8142 10 หลายเดือนก่อน +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.

  • @crazyst3ve01
    @crazyst3ve01 ปีที่แล้ว +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 ปีที่แล้ว

      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". -> th-cam.com/video/CLKZ7ZgVido/w-d-xo.html

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

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

  • @HartzFEAR444
    @HartzFEAR444 ปีที่แล้ว +11

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

  • @mindaugasw
    @mindaugasw ปีที่แล้ว +6

    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.

    • @DenisBabarykin
      @DenisBabarykin ปีที่แล้ว

      Agreed.

    • @softcodeacademy
      @softcodeacademy 6 หลายเดือนก่อน +2

      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.

    • @jkf16m96
      @jkf16m96 2 หลายเดือนก่อน +1

      that's the caveat but also the advantage of it.
      believe or not, there's a LOT of programmers that do not handle exceptions.
      And even when they do, they don't actually simplify the exceptions or even rethrow them.

  • @Danny1986il
    @Danny1986il ปีที่แล้ว +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.

  • @mhDuke
    @mhDuke 11 หลายเดือนก่อน

    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!

  • @iuribrindeiro5009
    @iuribrindeiro5009 ปีที่แล้ว +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.

  • @umairbutt1355
    @umairbutt1355 ปีที่แล้ว +23

    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 ปีที่แล้ว +1

      Our team is using it as well

  • @anreton
    @anreton ปีที่แล้ว +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.

  • @orterves
    @orterves ปีที่แล้ว +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...)

  • @gaxkiller
    @gaxkiller 6 หลายเดือนก่อน +1

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

  • @soonts
    @soonts ปีที่แล้ว +1

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

  • @cjamesrohan
    @cjamesrohan ปีที่แล้ว +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!

  • @allinvanguard
    @allinvanguard ปีที่แล้ว +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 ปีที่แล้ว

      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

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

  • @Aralmo640
    @Aralmo640 ปีที่แล้ว

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

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

  • @BenjiWright-r7x
    @BenjiWright-r7x ปีที่แล้ว

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

  • @ryan-heath
    @ryan-heath ปีที่แล้ว +5

    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.

  • @saffronomicon
    @saffronomicon ปีที่แล้ว

    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.

  • @Ankh.of.Gaming
    @Ankh.of.Gaming ปีที่แล้ว +4

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

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

  • @Kantragor
    @Kantragor ปีที่แล้ว +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

  • @uladzimirmalhin2379
    @uladzimirmalhin2379 ปีที่แล้ว +11

    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 ปีที่แล้ว +3

      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.

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

  • @MrSaydo17
    @MrSaydo17 ปีที่แล้ว

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

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

  • @nathancurnow2410
    @nathancurnow2410 ปีที่แล้ว

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

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

  • @nooftube2541
    @nooftube2541 ปีที่แล้ว +13

    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 ปีที่แล้ว +7

      If it succs then it is okay 😅

  • @nooftube2541
    @nooftube2541 ปีที่แล้ว

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

  • @MistyKu
    @MistyKu ปีที่แล้ว +8

    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.

  • @luiscamacho1917
    @luiscamacho1917 ปีที่แล้ว

    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

  • @nocgod
    @nocgod ปีที่แล้ว +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 ปีที่แล้ว

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

  • @raphaelbatel
    @raphaelbatel ปีที่แล้ว +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?

  • @_Aarius_
    @_Aarius_ ปีที่แล้ว +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 ปีที่แล้ว +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

  • @АртемБаляница
    @АртемБаляница 6 หลายเดือนก่อน

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

  • @proosee
    @proosee ปีที่แล้ว +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.

  • @Matt23488
    @Matt23488 ปีที่แล้ว

    Gotta love seeing concepts from languages like Rust make their way into C#

  • @diadetediotedio6918
    @diadetediotedio6918 ปีที่แล้ว +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 ปีที่แล้ว

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

    • @diadetediotedio6918
      @diadetediotedio6918 ปีที่แล้ว +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

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

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

  • @dcuccia
    @dcuccia ปีที่แล้ว

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

  • @scott98390
    @scott98390 ปีที่แล้ว +2

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

  • @JexsGG
    @JexsGG ปีที่แล้ว +2

    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  ปีที่แล้ว +3

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

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

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

  • @ethanshoham2855
    @ethanshoham2855 ปีที่แล้ว +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 ปีที่แล้ว

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

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

  • @OrgesKreka
    @OrgesKreka ปีที่แล้ว +1

    Looking forward for the LanguageExt video.

  • @ChristopherWodarczyk-hg6jm
    @ChristopherWodarczyk-hg6jm ปีที่แล้ว

    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.

  • @ΔεληγιάννηςΤάσος
    @ΔεληγιάννηςΤάσος 6 หลายเดือนก่อน

    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

  • @Mazzphysics
    @Mazzphysics ปีที่แล้ว

    I will def try it in my own projects.

  • @guybahar6856
    @guybahar6856 ปีที่แล้ว +2

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

  • @ronosmo
    @ronosmo ปีที่แล้ว

    Yes. I would like to wrap my head around functional.

  • @marna_li
    @marna_li ปีที่แล้ว +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.

  • @TheTortillaCurtain
    @TheTortillaCurtain ปีที่แล้ว

    Any more information about LanguageExt is always welcome.

  • @luki215
    @luki215 ปีที่แล้ว +5

    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 ปีที่แล้ว

      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.

  • @nikamamniashvili8633
    @nikamamniashvili8633 ปีที่แล้ว +1

    please make more videos on functional programing principes in c#

  • @nooftube2541
    @nooftube2541 ปีที่แล้ว +4

    The problem in this approach with exception that Result.Exception doesn't have stack trace.

    • @weluvmusicz
      @weluvmusicz ปีที่แล้ว

      Yes and this is the performance gain!

    • @nooftube2541
      @nooftube2541 ปีที่แล้ว

      @@weluvmusicz Sure, but it is not clear, you expect stack trace from exception. It is better to use some different class in such cases, when you don't need exception.

  • @dcuccia
    @dcuccia ปีที่แล้ว

    Yes! More functional discussions, please!!

  • @tarikpalic6304
    @tarikpalic6304 ปีที่แล้ว

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

  • @ianknowles
    @ianknowles ปีที่แล้ว

    Glad to see people advocating for this pattern but this is why I moved to Rust!

  • @BillieJoe512
    @BillieJoe512 ปีที่แล้ว +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)

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

  • @TheNorthRemember
    @TheNorthRemember 9 หลายเดือนก่อน +1

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

  • @neociber24
    @neociber24 ปีที่แล้ว

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

  • @sebastianroether2182
    @sebastianroether2182 ปีที่แล้ว +1

    It feels like shoehorning concepts into C# that arent well supported just because. I never have the problem of too much exception handling code but with this I would have to pass all the error states around everywhere all the time.

  • @mtsmithtube
    @mtsmithtube ปีที่แล้ว +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?

  • @maxpuissant2
    @maxpuissant2 ปีที่แล้ว +3

    And then after using it for each call you will find that you are copy/pasting the same error handling code and will want to abstract it? :D

    • @adrian_franczak
      @adrian_franczak ปีที่แล้ว

      you only need to match this in one place per request

    • @MaximilienNoal
      @MaximilienNoal ปีที่แล้ว +3

      Yeah I'm not a fan of it. It's C error codes all over again.

  • @creamyhorror
    @creamyhorror ปีที่แล้ว +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.

  • @xanhxanh5097
    @xanhxanh5097 ปีที่แล้ว

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

  • @totticheung674
    @totticheung674 ปีที่แล้ว +4

    What do you think about ErrorOr?

    • @kabal911
      @kabal911 ปีที่แล้ว

      I’m using ErrorOr now for most things, having previously used LanguageExt.
      It’s quite simple/basic, but it is easy to get people onboard.

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

  • @HiepDuong-q8f
    @HiepDuong-q8f ปีที่แล้ว

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

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

  • @shreyasjejurkar1233
    @shreyasjejurkar1233 ปีที่แล้ว +2

    Rust is great language!

  • @mcdev6868
    @mcdev6868 4 หลายเดือนก่อน

    Not sure if I am wrong but my expectation is something like if(result.IsSuccess) => DoSomething(result.Value). But with this Result class I can not do that, why would I need some overblown matching stuff? For some cases yes this might be good, but for me I don't see that.

  • @alexisfibonacci
    @alexisfibonacci ปีที่แล้ว +2

    Hot off the press!

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