How is this any cleaner than exceptions? Try-catch has type safety, you can have multiple catch clauses order by inheritance tree. Also, approaches like Either or Result end up being used on *every* layer of the architecture which is quite overwhelming, when on the other hand you can throw any exception from any layer and you can catch it in any layer you want/need without forcing the middle-man components to use a type and all this mapping.
Playing the devil's advocate here: Some of the challenges with exceptions is that they are implicit and not part of the signatures. If something like Java's checked exceptions were used then passing higher order functions wouldn't work. The problem with being implicit is that the only way you can know if the exception can/will occur is if they are documented or if you have access to the source code. Using algebraic data types (sealed class hirearchies) allows you to make the errors (exceptions) explicit so that the calling code can see what needs to be handled just by looking at the code signature. Exceptions are also fairly expensive to create and throw relatively speaking. If this trade-off is worth it depends on more than just comparing try/catch with a monad like Either, in my opinion.
So I get that Arrow is trying to make Either completely generic, but Either.Left and Either.Right is very non-descriptive from a code readability standpoint. Something like Result.Success / Result.Failure would be way easier for someone unfamiliar with the code to immediately grasp. I've tried Arrow, and while there are some good ideas in it, there's a massive learning curve and a lot of very unintuitive code. There's also a staggering amount of namespace pollution in the library. I want to like it, but I can't help but feel that extracting concepts from it on a case-by-case basis and implementing them yourself with better naming practices leads to considerably cleaner code and a better development experience.
How is this any cleaner than exceptions? Try-catch has type safety, you can have multiple catch clauses order by inheritance tree.
Also, approaches like Either or Result end up being used on *every* layer of the architecture which is quite overwhelming, when on the other hand you can throw any exception from any layer and you can catch it in any layer you want/need without forcing the middle-man components to use a type and all this mapping.
Playing the devil's advocate here: Some of the challenges with exceptions is that they are implicit and not part of the signatures. If something like Java's checked exceptions were used then passing higher order functions wouldn't work. The problem with being implicit is that the only way you can know if the exception can/will occur is if they are documented or if you have access to the source code. Using algebraic data types (sealed class hirearchies) allows you to make the errors (exceptions) explicit so that the calling code can see what needs to be handled just by looking at the code signature. Exceptions are also fairly expensive to create and throw relatively speaking. If this trade-off is worth it depends on more than just comparing try/catch with a monad like Either, in my opinion.
So I get that Arrow is trying to make Either completely generic, but Either.Left and Either.Right is very non-descriptive from a code readability standpoint. Something like Result.Success / Result.Failure would be way easier for someone unfamiliar with the code to immediately grasp. I've tried Arrow, and while there are some good ideas in it, there's a massive learning curve and a lot of very unintuitive code. There's also a staggering amount of namespace pollution in the library. I want to like it, but I can't help but feel that extracting concepts from it on a case-by-case basis and implementing them yourself with better naming practices leads to considerably cleaner code and a better development experience.