3 ms·
It's ironic how PHP's philosophy of "ignore errors and keep chugging along" has lead to developers habitually adding "or die()" (crash on error) to everything,
by wongarsu 1y ago
It's ironic how PHP's philosophy of "ignore errors and keep chugging along" has lead to developers habitually adding "or die()" (crash on error) to everything, even in this instance where chugging along at any cost would have been the exactly right behavior
I wonder if they would have spent more thoughts on error handling in a language that defaults to crashing on error (e.g. Java's exceptions)
- brabel 1y agoForcing developers to handle errors properly is a difficult thing to do in any language. Their solution to use JavaScript kind of surprised me: yes, `exit()` is not something common in JS, but if the code to send email threw an exception (instead of returning a boolean, which seems to be the case here) it would probably exit as well, but in an implicit manner, worse than `or die`. However, Java has checked Exceptions which would force you to handle the possibility explicitly or the code would not compile, but the Java experience shows that almost always, people will just do: try { sendMail(); } catch (CannotSendMailException e) { throw new RuntimeException(e); } Or even just log the Exception (Which would actually be the right thing to do in the case of the study!). With Go's multiple return values to represent errors, they are also known to be too easy to "forget" to even look at the error value. With Rust's approach, which is using sum types to represent either success or error (with the `Result` type), it is impossible to forget to check, like Java checked Exceptions... but just like in Java, arguably even easier, you can just sort of ignore it by calling `unwrap()`, which is fairly common to do even in production-level Rust code (it's not always wrong, some very prominent people in the Rust community have made that point very clearly... but in many cases that's done out of laziness rather than thought), and is essentially equivalent to PHP `or die` because it will panic if the result was an error.
- gleenn 1y agoI understand what you're saying about the potential annoyance or dissatisfaction with Java checked exceptions being effectively cast to Runtime ones. As a language choice, it made a signal by differentiating checked versus unchecked and at least gave user the opportunity to benefit from a choice witha nudge in the right direction. You always have to have the escape hatch, but making it less "affordable" to the user, they tend to do the right thing more often which sounds like a perfect win given the trade-offs.
- wongarsu 1y agoYou can't force developers to handle errors correctly (outside code review). But maybe you can change what their first thought or habitual action is. In go or rust for example the habitual behavior is to throw the error upwards. In go with a three-line if statement, in rust with a simple `?`. In php the habitual behavior is to crash on error. As you point out that's not that different. Maybe a better example of the opposite would be python, with its unchecked exceptions. One of my first thoughts in python error handling is "here I don't want exceptions to propagate, let's throw in a lazy `try ... except print(...); sleep(1)`. But I'm not sure I actually do that more than e.g. in rust, simply because I write them in so different environments (my python code just has to run and produce correct results, my rust code is rolled out to customers and has to pass code review)
- Terr_ 1y agoI often find myself wishing for a Checked Exceptions, I think things would have played out differently if there was more syntactic sugar. Like if one could easily specify that within a certain scope (method or try-block), any of a list of exception classes (checked or unchecked) will become automatically wrapped into a target checked exception class as the chained "cause." So you could set a policy that EngineBrokenException=or OutOfFuelException bubbling up will become FleetVehicleInoperableException.
- eeue56 1y agoAuthor here! In this case, I think the actual API we used would take a callback for success, and a callback for errors. I just used JS an example for how unnatural it would be to call something that exits the entire script early. I have a big problem with promises + exceptions generally in JavaScript - much preferring union types to represent errors instead of allowing things to go unchecked. But I left that out as it was kind of a side-note from the point of affordance.
- layer8 1y agothrow new RuntimeException(e); Linters like SpotBugs tend to complain about that. But it’s also a matter of naming. If RuntimeException was instead called something like ProgramBug, people might be more reluctant. In the end, it’s an issue of education. People need to be aware of the possible consequences, and have to be taught how to properly handle such cases. There is no way to automate error handling without the developer having to think about it, because the right thing to do is context-dependent. Checked exceptions at least make the developer aware of failure modes to consider.
- kirici 1y ago>With Go's multiple return values to represent errors, they are also known to be too easy to "forget" to even look at the error value. How? Unassigned foo := myFunc() # [...] assignment mismatch: 1 variable but myFunc returns 2 values Assigned, but not used foo, bar := myFunc() fmt.Println(foo) # [...] declared and not used: bar Intentionally ignored foo, _ := myFunc() Ignoring is a deliberate decision and trivial to review, lint and grep for. Except for, I suppose, shadowing a variable before checking it foo, bar := myFunc() _, bar = myFunc() fmt.Println(foo, bar) Which is more of a general grievance of quite some people, but I don't think that has much to do with multiple returns - and you definitely have to look at the error to pave over it afterwards. edit: https://goplay.tools/snippet/E69xFuIcG7I https://goplay.tools/snippet/E69xFuIcG7I
- brabel 1y agoYou're right, Go errors if you do not use a value, so it's very hard to forget to check for the error. I might have been thinking about another language, consider my comment about Go retracted.
- Ferret7446 1y agoThis is why a lot of Go users like its error handling as it is. It forces you to explicitly think about how you want to handle the error. Of course, it can't prevent people from pasting an error handler everywhere instead of thinking about it, which I think are the same people who hate Go's error handling
- PaulKeeble 1y agoTechnically it doesn't because you can just ignore the error return and keep going anyway, its only a lint failure not to do something with a returned error. The language has a culture of dealing with the error straight away but the language doesn't enforce it. In Java with checked exception you have no choice, you either try/catch it or you throw(s) it and are forced to handle it or its a compile error. Java does this aspect better, error handling features are relatively weak in Go but people have utilised the multiple returns well to make the best of it.
- thaumasiotes 1y ago> In Java with checked exception you have no choice, you either try/catch it or you throw(s) it and are forced to handle it or its a compile error. Java does this aspect better You don't have to give any consideration to that if you don't want to; you can always just catch the exception and rethrow it as a RuntimeException.
- tcfhgj 1y agoI "hate" GOs error handling because of repetitive and verbose boiler plate when it comes to error handling. Rust has almost the same error handling concept, but with way less boilerplate. And Rust actually syntactically forces to handle the error case, because you can't just access the return value when there are potential errors
- ansc 1y agoI think they are actually pretty different in approach. rust sprinkle ”?” everywhere and wants to avoid dealing with the error, and golang is more explicit and robust handling. sure, most is similar if it is just ”if err return err” but I have definitely seen more ”extreme” and correct error handling in golang, whereas in rust the convenience of just bubbling it up wins. I still prefer rust, but I am not sure the comparison is as close as people claim