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 Жыл бұрын
Definitely cover more functional stuff! This kind of content is exactly what we love to see, practical application of functional concepts.
@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 Жыл бұрын
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 Жыл бұрын
Today is the first time I've heard of "railway pattern", why does this make so much sense.
@dolgan12 Жыл бұрын
Welcome to F# :)
@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.
@gileee4 ай бұрын
@@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 Жыл бұрын
I've used this sort if pattern for over 10 years and it has never let me down! :)
@iuribrindeiro5009 Жыл бұрын
This is probably a better introductory video: kzfaq.info/get/bejne/i7lohKpqrpe8h2Q.html
@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 Жыл бұрын
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 Жыл бұрын
@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
@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 Жыл бұрын
Our team is using it as well
@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-gn7bd6mq8n6 ай бұрын
would u plz share ur ApiResult class?
@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 Жыл бұрын
Lol same. I was also watching his same video and actually looking if he had a video on Results.
@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 😂
@gveresUW Жыл бұрын
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.
@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 Жыл бұрын
But isn't that the purpose of nullable types?
@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
@fsharpfan Жыл бұрын
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 Жыл бұрын
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.
@fredericbrown88718 ай бұрын
@@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.
@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).
@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.
@gaxkiller4 ай бұрын
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 :)
@twiksify Жыл бұрын
Have a peek at rust Option and Result for some other useful extensions which are quite simple to implement yourself.
@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 Жыл бұрын
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". -> kzfaq.info/get/bejne/ebJ7jZqLzLzNlKM.html
@obinnaokafor6252 Жыл бұрын
@@iuribrindeiro5009 DO you know that there is something called industry standard languages and growing languages? And toy languages?
@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 :)
@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.
@DryBones111 Жыл бұрын
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.
@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.
@mindaugasw Жыл бұрын
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-fu6mp6et8p11 ай бұрын
Agreed.
@softcodeacademy4 ай бұрын
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Ай бұрын
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.
@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.
@HartzFEAR444 Жыл бұрын
5:16 "I'm gonna link them in the description below" - you forgot :(
@michaelrall81429 ай бұрын
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.
@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 Жыл бұрын
hello, could you please give me the link to the code about this idea (converting object result to IActionResult)
@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. :)
@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.
@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 Жыл бұрын
He does not use f#
@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.
@Danny1986il Жыл бұрын
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.
@soonts Жыл бұрын
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);`
@nathancurnow2410 Жыл бұрын
I really like that you pretty much just reimplemented the Rustlang Result enum. Great work!
@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 Жыл бұрын
If it succs then it is okay 😅
@mhDuke9 ай бұрын
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!
@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.
@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!
@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 Жыл бұрын
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
@Ankh.of.Gaming Жыл бұрын
I find myself using this very often in C# ever since I started learning Rust. Go figure.
@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 Жыл бұрын
Option is not the same as nullable. You can wrap it, but it is different.
@allinvanguard Жыл бұрын
@@crazyst3ve01 Sure, it's not the same, but the semantics are similar enough for most use cases
@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...)
@MrSaydo17 Жыл бұрын
Been using Result for 5+ years. I can't live without it.
@DrHeinzDoofenshmirtz Жыл бұрын
I have jumped on this Flow Control as well with the ErrorOr library which is awesome! It supports returning multiple errors as well.
@Aralmo640 Жыл бұрын
I do love the result approach, specially when coupled with linq syntax to avoid the nasty nesting it usually creates.
@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 Жыл бұрын
😳 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 Жыл бұрын
@@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 Жыл бұрын
@@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. 🥲😁
@saffronomicon10 ай бұрын
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.
@user-km7fd2le8f Жыл бұрын
Yes, I'd love a video about functional concepts like Some, None, Unit, etc.
@nooftube2541 Жыл бұрын
Also you can use Try...(out result) patter. You can also add out failure to signature if you need.
@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?
@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
@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
@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 Жыл бұрын
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 Жыл бұрын
@@RobinHood70 not a lot in most cases. Plus usually it used for classes, so everything already boxed.
@nocgod Жыл бұрын
@@RobinHood70 you might pay some price. Easily testable with benchmarkDotNet:)
@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...);
@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 Жыл бұрын
if you use for error something like rust enums you don't need extra parameters
@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.
@_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)
@dcuccia Жыл бұрын
Yes! More functional discussions, please!!
@user-qi7mk6be7u4 ай бұрын
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
@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.
@user-fr7nn1yq3m4 ай бұрын
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. 🙂
@dcuccia Жыл бұрын
Great video, thanks. Look forward to a day where we can use switch expressions with DU deconstruction.
@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 Жыл бұрын
Interesting question. A lot of SDKs do use exceptions for things like 404, 409 and 429.
@shreyasjejurkar1233 Жыл бұрын
Rust is great language!
@OrgesKreka Жыл бұрын
Looking forward for the LanguageExt video.
@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
@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.
@nooftube2541 Жыл бұрын
The problem in this approach with exception that Result.Exception doesn't have stack trace.
@weluvmusicz Жыл бұрын
Yes and this is the performance gain!
@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.
@Mazzphysics Жыл бұрын
I will def try it in my own projects.
@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).
@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 Жыл бұрын
I use both. I use OneOf generally and I have a result type through oneof
@luki215 Жыл бұрын
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 Жыл бұрын
This is coming natively in C# as a feature as well
@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.
@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 Жыл бұрын
I'm working on exactly the same 😂 very interesting to dive into the roslyn analyzers
@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
@scott98390 Жыл бұрын
First time I've seen the PureAttribute - can you go into detail on that?
@Matt23488 Жыл бұрын
Gotta love seeing concepts from languages like Rust make their way into C#
@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.
@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)
@alexisfibonacci Жыл бұрын
Hot off the press!
@totticheung674 Жыл бұрын
What do you think about ErrorOr?
@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.
@ianknowles Жыл бұрын
Glad to see people advocating for this pattern but this is why I moved to Rust!
@tarikpalic6304 Жыл бұрын
Man, I just got used to working with OneOf library, and now you come up with this :D
@nikamamniashvili8633 Жыл бұрын
please make more videos on functional programing principes in c#
@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.
@slowjocrow64519 ай бұрын
This was a spooky one. Terror everywhere
@jammycakes Жыл бұрын
This approach needs to come with a massive health warning: it should NOT be a replacement for exceptions and it should NOT be your default way of dealing with error conditions. It should only be kept for very specialised use cases such as validation where you need to handle very common, well-defined and expected error conditions as soon as they are encountered. There is a very good reason why we use exceptions: they do the safe thing by default. If your code reports an error, it is almost never appropriate to continue regardless; if you did, your code would end up running under assumptions that are incorrect. At best this would result in more errors; at worst it would result in silent data corruption that might not become apparent until it's done a lot of irreparable damage. This is where exceptions shine, because they do the appropriate thing by default, bailing out and propagating up the call stack until they encounter a handler that can deal with the situation properly. By contrast, with Result, the default option is the dangerous one, and you need to add some repetitive boilerplate code after every method call to handle it.
@reikooters Жыл бұрын
But from what I see in the video, he is using it to handle expected error conditions. If an exception was thrown because something exceptional occurred, wouldn't it still bail out as you say? If I understand your comment, it sounds like you're talking about catching any and all exceptions then returning them in a Result, otherwise how would it keep going. I'm of the opinion that exceptions should be for exceptions. If a function call had an expected error, then handle it, even if it means the request can't continue and you return a bad request.
@matthewr8502 Жыл бұрын
Rust says hello and points out that in a safe and robust language with result and option types you don't need exceptions at all and your code becomes much cleaner and easier to reason about. Exceptions are just bad way of dealing with control flow and errors and make your programs much more complicated than they need to be.
@jammycakes Жыл бұрын
@@reikooters If the error conditions are expected, well defined and narrow in scope then yes, Result may be appropriate. Examples include such things as TryParse and TryCreate, or requesting a resource that may or may not exist, or validation. But that is something that needs to be made clear, otherwise you will end up with people using Result for everything, and getting into trouble as a result.
@themiwi Жыл бұрын
This is at least very misleading. Yes, fatal errors should be fatal. But that is not what most people use exceptions for. They have become some sort of goto statement and abused for flow control. A file or directory doesn't exist or can't be accessed? For interactive applications this certainly isn't a fatal condition. The error should be communicated to the user instead, letting them pick a different file or folder. Yet, the Microsoft API's for filesystem access throw instead of forcing you to appropriatelyhandle the situation in the calling function. Forgot that try-catch? Too bad. Boom. Imagine your IDE shutting down everytime there's a syntax error in your code? Yeah, ridiculous. That's why in virtually every safety critical domain I've ever seen, exceptions are tightly regulated and only allowed for truly fatal situations.
@jammycakes Жыл бұрын
@@matthewr8502 Really? If exceptions are a bad way of dealing with control flow and errors, and really do make your programs much more complicated than they need to be, then exactly what problems do they cause and exactly what complications do they introduce? Remember: "safe and robust" means that you make it easier to get things right and harder to get things wrong. That means, among other things, making the safe course of action the default. As I said, continuing regardless after an error has been encountered is not a safe course of action and should not be the default.
@mtsmithtube Жыл бұрын
What if your repository throws an exception? It looks like it would bubble up to your controller which no longer has a try/catch?
@TheNorthRemember7 ай бұрын
5:19 where are those vids you talked about exception flow control
@guybahar6856 Жыл бұрын
Hi Nick, What is the different from the package OneOf ?
@TheTortillaCurtain Жыл бұрын
Any more information about LanguageExt is always welcome.
@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
@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.
@neociber24 Жыл бұрын
If they ever stabilize the new enum types this will be even better
@Kotz_en Жыл бұрын
How different is this from OneOf?
@ronosmo Жыл бұрын
Yes. I would like to wrap my head around functional.
@ershadnozari Жыл бұрын
Brilliant, thanks!
@maxpuissant2 Жыл бұрын
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 Жыл бұрын
you only need to match this in one place per request
@MaximilienNoal Жыл бұрын
Yeah I'm not a fan of it. It's C error codes all over again.
@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.
@sebastianroether2182 Жыл бұрын
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.
@Palladin007 Жыл бұрын
Why always the Match or Map method? Why not a simple if or the ternary conditional operator? return result.IsSuccess ? DoSomethingWithResult(result.Result) : DoSomethingWithWith(result.Error); Looks clearer to me, is more flexible and avoids the delegate instances. And it also works with nullable reference types.
@nickchapsas Жыл бұрын
Because you are not forced to do it
@victor1882 Жыл бұрын
You could, I actually use both depending on the use case. The good thing about Match is that it forces you to handle both cases and also extracts the type from within the result, so you can give a better name to that than result.Value or result.Result
@valera924 Жыл бұрын
Because the Map and Match methods can be easily chained
@JinnGuild Жыл бұрын
Chaining, as Valera says. But also, Monadic approaches have their own context and semantics. With using the traditional if/then, you're not forcing yourself to continue to return more monads. You're sucking out the value and operating on it. But if you use Monadic semantics and methods like Bind and Map (sometimes Match), you both consume a Monad, and you return a Monad. Using result.Result outside of Map/Bind/Match makes this pattern lose its power.
@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👌👌
@mcdev68682 ай бұрын
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.
@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.
@user-nw7jo5xw9x Жыл бұрын
if i'm not mistaken, it is the rust way to return error or result