Комментарии:
what if TLeft is void?
ОтветитьEven though I love sum types, c# was not meant to be used with them. Nothing will make your colleagues and people inheriting your code-base resent you more than using arcane/opinionated coding patterns instead of industry conventions.
Don't get me wrong, I love Result<T, err> and Option<T> in rust or F# or zig, or o'caml but c# was not geared for it as of yet.
You can decorate the methods with throws...description
ОтветитьI think I would be more in favor of this approach if the compiler could guarantee that a method with an explicit type didn't throw an exception. The problem here is 3rd party code can still throw and you need to handle it. This approach is more explicit, but it's going to be jarring to developers that are used to exceptions.
ОтветитьToo complicated and unclear usage. It looks like you are trying to write fancy, instead of simple an effficiant.
The sultation should be in the function documentation.
associating this with "honesty" is intellectually dishonest
ОтветитьGreat video! But I would probably name the properties of Either to something else. For example: "ok" and "fail" to make it even more explicit.
ОтветитьHow would you scale the idea to 5, 10, 100 possible error scenarios? Having Either<int, Exception> isn't any better than just int. 10 layers of nested generics is a nightmare... Creating generic variants of Either<> with every possible errors count? Still look scary...
ОтветитьYou can also add operator overloads for implicit casting which will remove quite a bit of boilerplate code when returning Either.
ОтветитьVery good idea. Especially helpful at the service layer. However, I'd still use exceptions below the service layer as exceptions will always halt operation and don't need special handling/redirect at the parent level.
ОтветитьHi! Thank you for the video. I really enjoy checking different ways to code. But using this approach wouldn´t add more if checking on your code? On your method AddItemToBasket, the line 29, UpdateAsync would be called even no item was added to Basket. In this case would case no harm, I guess, but in other case it could... So, would it add many more guard clauses? Could you clarity this, please? Thank you very much!
ОтветитьNice video. More people should use this approach to error handling. Although, the convention in functional languages like Haskell is to use left for the error and use right for the "right" value.
ОтветитьYou're recreating Rust's Result type, and match system.
ОтветитьI don't enjoy this video :) I think you're clogging up your code on this... It looks like old "ContinueWith" problem. How can I know what is the Either "pattern"? I have to read documentation. How can I know about exception? I have to read documentation. How can I say about exceptions to my customer? Just write "exception tag" in "xml-summary"...
ОтветитьThat's useful when you know how many exceptions can be raised (specially when they are not so much), and also when your program flow doesn't pass-through library dependencies.
But, how to deal with their exceptions?
Evenmore, what to do when your exceptions are handled externaly, such logging them
This sample shows a gentle manner of dealing with a 2-cases result, but that's a kind of panacea.
I don't know C# very well, but this approach seems pretty Rusty!
I've been thinking about doing something like this in typescript.
:)
OverEngineer imo. Just throw exception and have a globalexception middleware to take care of it.
ОтветитьHow would you handle exceptions thrown in constructor? Can't return either from constructor, but we could use NullObjectPattern maybe or something similar in a sense, that hold the validationresult or just an exception, if there is just one?
Make a new class than inherits from the one we want to create and return an instance of that instead?
Something I've learnt from golang. Errors as first class. Most methods explicitly tell you if you have a returned result or an error. Exceptions are exception to what you believe your code does.
ОтветитьException should only be used when something horribly gone wrong and application have to terminate. The biggest problem it breaks the flow of code. For me the definition of function/method is a processing mechanism that takes in input and returns processed output. Exceptions really break that definition. Exceptions really make methods unpredictable. You can't say how will the method call behave if the method throws because it will break the whole code flow. And who can forget the issues of exceptions with async/task. Async with exception is a nightmare for beginner programmers you dont await or do continuewith exception gets ignored, sometime stack trace get messy and hard to understand whereas simple input-output behaviour of methods makes concurrency a piece of cake. And who can forget the performance issues. Exceptions can decrease the the performance drastically(I mean horribly).
Exceptions are really anti pattern for modern scale apps. If that's not the case why didn't modern languages didn't adopt exceptions?
I have some advice for you: please look up why C# does not have checked exceptions.
ОтветитьAm I the only one who hates the name of the Either type? I prefer the name Result instead
ОтветитьAnother way to fix it is to not represent quantity as an int but instead as a custom Quantity type and make the impossible state like quantity < 1 impossible to compile. Not sure how painful the would be in c# but that’s how I would fix that particular issue in typescript.
ОтветитьNice video! in golang we've "return &Entity, error" way to return either the expected result, either the error. Looks similar to me to golang way to talk ))))
ОтветитьCan you explain how you would deal with multiple either types in a mehtod? I can imagine this getting ugly quick.
ОтветитьYou successfully injected exception in function signature. So you showing it clear that it might happen. What to do if underlying function has 25 different exceptions? They're all can happen.
are you inclure in signature their common base class effectively hiding them back again?
Both Either and Maybe functional structures are amazing ways of doing a more explicit code flow. Excellent tip!
ОтветитьI like the idea of explicit contracts. Bertrand Meyer's design by contract was a good idea, and we could do similar things today to improve our contracts but it was ultimately rendered useless by unit tests, think of your unit tests as your contract (packages maybe a different story, but honestly it's your own fault if you blindly trust a package). The benefit of throwing an exception is that it forces the application to stop and forces the client to deal with it. As opposed to continuing to function and accidently returning success statuses because the client didnt handle it. Those can be so horrible to debug.
ОтветитьEh.. this seems like a bad idea to me..
ОтветитьGreat video, I have done the same thing in a project in Java.
Ответитьnice approach. Thanks! :D
ОтветитьNice. Something I do. Something I want to do better. Now, are exceptions so bad that we can't even digest or handle them and return some failure response by implementing some level of indirection?. Wanted to know your overarching thoughts.
ОтветитьI don't like mixing functional-style with OO style error handling. Being explicit could just mean documenting that addItem can throw an exception.
ОтветитьI like this! Thanks for sharing.
ОтветитьBut exceptions can be handled globally.. where we can apply logging.. here I don't see the logging implementation
ОтветитьIt looks good, and it can be used somewhere in projects..
ОтветитьIt looks like how golang handle errors and many people blame golang because of it :))
ОтветитьIn this case the throwing method returns the quantity. It would be possible to just return 0 if quantity is less than 1. Exceptions provide a way to break execution during development which is invalidated with this implementation. Exceptions are meant to be thrown where they happen so I would use a dedicated error class instead. Returning multiple values is of course a good idea.
ОтветитьWhat happens if you have multiple errors? It's either inside either?
Ответитьwhy don't you just return a result object?
IResult<T> {
String Status {get;}
bool HasError {get;}
String ErrorMessage{get;}
T ResolutObject{get;}
}
I ussually have methods that throw more than one type of exception. How do you handle these scenarios?
ОтветитьWe have enjoyed this in nodejs for over a decade. Leave the throwing and error handling to high level consumers. We create the errors internally but never throw them. Nodejs is known for the (err, result) callback pattern which is very similar to your Either Type implementation here.
ОтветитьFrom Haskell?
ОтветитьA tool to have for sure. But I would go with a combination of exceptions and results. In general there are many situations when you can't handle an exceptional situation which usually results in 500, logs, some general exception handler logic, etc... and thats fine. No need for additional abstractions, or complexity (if implemented poorly).
ОтветитьNice video. Also "Either" can be a struct and with that avoid null reference exception, and you can use implicit operators to directly return the TLeft or TRight without having to make a new Either object from the AddItem method, like this:
public struct Either<TLeft, TRight>
{
private readonly TLeft _left;
private readonly TRight _right;
private readonly bool _isLeft;
private Either(TLeft left, TRight right, bool isLeft)
{
_left = left;
_right = right;
_isLeft = isLeft;
}
private Either(TLeft left) : this(left, default, true)
{
}
private Either(TRight right) : this(default, right, false)
{
}
public static implicit operator Either<TLeft, TRight>(TLeft left)
{
return new Either<TLeft, TRight>(left);
}
public static implicit operator Either<TLeft, TRight>(TRight right)
{
return new Either<TLeft, TRight>(right);
}
public T Match<T>(Func<TLeft, T> left, Func<TRight, T> right)
{
return _isLeft ? left(_left) : right(_right);
}
}
* Then you can "return new InvalidOperationException()" or "return existingItem.Quantity"