4 ms·
The arguments here against try/catch are superficial and in no way compelling enough for me to adopt this pattern for error handling. Seems to be a solution loo
by jtdev 7y ago
The arguments here against try/catch are superficial and in no way compelling enough for me to adopt this pattern for error handling. Seems to be a solution looking for a problem... stop trying to be so clever - focus on writing clean, readable, simple code.
- cousin_it 7y agoAgreed. I never understood the love for Either-based error handling in Haskell and other languages. It's such a bare bones system. If you add all the features that people want from an error handling system, like stack traces; and remove the misfeatures that nobody wants, like Either<IOError,Either<MathError,Result>> being a pointlessly different type from Either<MathError,Either<IOError,Result>>; you end up with (surprise!) try-catch.
- roblabla 7y agoI'm not familiar with Haskell, but Rust's `Result` type is the same idea, and I wouldn't want to trade it for try-catch. It supports backtraces[0], has a simple way to turn errors into a "catch-all" type[1], but it is significantly less complex since it reuses the basic return value mechanism a function has. If you want to exit the program because the error can't be handled (similar to an unhandled exception), rust has a different concept for it, panics, and any Result can be turned into a panic via `unwrap()`. IMO both are important: panics represent unrecoverable errors, while Results can be acted upon (for instance, if read() returns Err(EINTR), you'll want to retry the read) [0]: Granted, you need to write some boilerplate to get the backtrace on error creation. [1]: You can cast all errors to `Box<dyn Error>`, a heap-allocated dynamically dispatched Error type.
- kmonsen 7y agoSo in rust you write with result and in js you use try/catch. Pretty simple, and readers will understand the code.
- roblabla 7y agoOh I agree, and definitely don't recommend using Result in JS, the language is just not tailored for it. I was specifically addressing > I never understood the love for Either-based error handling in Haskell and other languages.
- lmm 7y ago> If you add all the features that people want from an error handling system, like stack traces; and remove the misfeatures that nobody wants, like Either<IOError,Either<MathError,Result>> being a pointlessly different type from Either<MathError,Either<IOError,Result>>; you end up with (surprise!) try-catch. What does a function that doesn't error look like under try-catch? How do you tell it apart from a function that can error. It's the same argument as null/Optional. Yes, Optional behaves the same as a nullable value; the point is that languages with Optional allow you to have values that aren't nullable.
- cousin_it 7y ago> What does a function that doesn't error look like under try-catch? How do you tell it apart from a function that can error. By the empty throws clause.
- lmm 7y agoEdit: Parent was edited, previously suggested "Java-style exception specifications". As far as I know every language with "throws clause"s has the kind of problems I describe below though. Three major problems: they interact inconsistently with generics, you can no longer take a function's result and store it as a value, and you still can't tell whether a function might throw by looking at the point where it's called. A good version of exception specifications would be lightweight syntax sugar over either (in the same way that a good version of async/await is a lightweight syntax sugar over futures/promises). But I'm not aware of any language implementing that; I guess once you have working Either there's not enough value in providing an alternative syntax for it.
- deleted 7y ago[deleted]
- cousin_it 7y agoActually I thought a bit and realized that I don't want to defend checked exceptions. Let me amend the previous answer to "I prefer such functions to be interchangeable".
- chii 7y agowhy is either wrapped in eithers in your example? That feels like wrong code to me. Wouldn't it be Either<(MathError|IOError), Result>, and you pattern match the error or result?
- 0815test 7y agoThe types are definitely isomorphic, but the difference between them is not "pointless". You could have Either<IOError, Either<IOError, Result>> and want to preserve the information about which step led to an IOError outcome.
- deleted 7y ago[deleted]
- cousin_it 7y agoThat information shouldn't be in the type, because it makes functions pointlessly non-interchangeable. With try-catch, a superset of that information is preserved in the stack trace, and functions stay interchangeable.
- esarbe 7y agoI consider the error types to be a useful information that should absolutely be part of the method type. If a method can fail on IO that's different than if it cannot fail. And the surrounding code has to account for that. So, you might think that the methods are interchangeable if the error type is not present in the signature but this is actually wrong. Different failures have to be handled differently. (I assume that you are /not/ talking about valid error cases in the problem domain that also might have to be handled)
- deleted 7y ago[deleted]
- lmm 7y ago> stop trying to be so clever - focus on writing clean, readable, simple code. That's exactly what using either instead of try/catch does! try/catch are magic language keywords that create invisible, surprising control flow. Either is plain old code written in the normal language, with functions that follow the normal rules.
- jtdev 7y agoAll language keywords are “magic” to some degree. The control flow that try/catch creates has never been surprising or invisible in my experience.
- cheeze 7y agoFully agree. IMO this is the same argument as "the for loop is a magic keyword" which just isn't true. Try/catch makes it _incredibly_ clear what you're trying to do. Kids who graduate college and get their first real job understand what a try/catch does. A random contributor to an OSS project knows what try/catch does. Meanwhile, I'd be willing to bet that not even 10% of programmers could actually explain what a monad is. I'm sure there is a place for this elegant error handling, but in most codebases it seems like a pretty big complexification for not all that much benefit. Sure, the code might even be "more correct" (whatever that means), but if Samantha the intern can't pick it up rather quickly, it probably isn't all that well suited for mainstream usage.
- lmm 7y ago> IMO this is the same argument as "the for loop is a magic keyword" which just isn't true. The for loop is indeed a magic keyword, though it's less surprising/magic than try/catch; most of what for does could be done by a plain old function. > Meanwhile, I'd be willing to bet that not even 10% of programmers could actually explain what a monad is. Don't try to generalize prematurely. Considering Either on its own, it's simpler than try/catch and can replace their use cases. If you'd started with Either, try/catch would seem like the overcomplicated solution in search of a problem that it is.
- MapleWalnut 7y agoMaybe in plain JS, but with Typescript this Either pattern will force you to handle errors unlike untyped try, catch.
- namelosw 7y agoI don't use this pattern to deal with the problems in my day to day JavaScript code in case other people confuse. I just think it's unfair to simply believe this is complex. It's simpler on mental. I'm not encouraging people to use this style, it's just some random defense. This pattern is not more complex than try/catch. It's just JavaScript lack constructs to make the writing much less verbose. (we could abuse async/await but it's tricky). Try/catch is an extra language construct which is confusing - it has dynamic semantics just like JavaScript's weird 'this' behavior. And it's leaky just like null - when you forgot to handle something, the whole thread explodes. Besides, it's not an expression, which means it's harder to refactor or return with function, passing as an argument, etc. On the contrary, Either would be just fine everywhere, just typical functions and values. Another use case is when you want to collect the errors along the road, instead of failing fast behavior, in this case, Either would be easier than try/catch.
- dyeje 7y agoIt may not be complex, but it's certainly obscure. Any JavaScript developer could understand the try/catch example but many would struggle with the Either example.
- deleted 7y ago[deleted]
- ahallock 7y agoSaying something is superficial and too clever is not a counter argument, but rather a reaction, I think, to it being radically different from what you're used to. I'm not saying it's necessarily better, but maybe approach things with an open mind.