Timeline for Avoiding throw because we are not sure the exceptions will always be caught
Current License: CC BY-SA 4.0
Post Revisions
49 events
| when toggle format | what | by | license | comment | |
|---|---|---|---|---|---|
| Apr 22, 2024 at 23:39 | comment | added | Aaron Newton | I imagine this is a variation of the "Notify, don't throw" guideline that Martin Fowler talks about here: martinfowler.com/articles/replaceThrowWithNotification.html. In short, notifying implementers of validation issues is not considered exceptional behaviour, and if there's more than one issue, you risk raising an exception early before all notifications can be generated. A language that has this mindset "baked-in" is Golang, which encourages the "comma okay" pattern for things like accessing map keys which may not exist. go.dev/doc/effective_go#maps. | |
| Apr 22, 2024 at 22:24 | comment | added | Simon Geard | @Ben - exactly. Crashing isn't ideal, but it's often preferable to continuing in an unsafe state, which can lead to much larger data corruption problems than if the code aborted at the first sign that something was wrong. | |
| Apr 22, 2024 at 16:14 | comment | added | supercat |
@Ben: Having an "invalid formula" object's "evaluate()" function return NaN would be a safe default behavior that would require very little logic elsewhere in the program to deal with. The part of the code that displays a cell's value should likely check whether the cell's evaluation function has more information about why it yielded NaN (e.g. "invalid formula", "square root of negative number", etc,.) but evaluation of other cells that use the invalid cell's value wouldn't need to take such factors into consideration (they could report "Cell D7 was NaN" without caring why D7 was NaN).
|
|
| Apr 22, 2024 at 12:08 | answer | added | Dreamer | timeline score: 1 | |
| Apr 22, 2024 at 8:04 | comment | added | Ben |
@sayanel Yes, but you might have to throw in order to reach a part of the code that can not leave the app in an invalid state. In your Excel example, a Formaula constructor that is given invalid input could construct a Formula object that doesn't work, or it could throw. If it throws, then to not crash the app the UI code for entering formulas needs to handle the error. If invalid Formula objects are possible, then every other piece of code in the entire codebase that uses Formula objects needs to handle them being invalid. "Not crashing" is easier with the throw design.
|
|
| Apr 22, 2024 at 6:40 | comment | added | sayanel | But they are other means of returning errors, and these means are guaranteed to never crash the app | |
| Apr 22, 2024 at 6:29 | comment | added | Bart van Ingen Schenau | @sayanel, an invalid formula should indeed not crash Excel, but on the other hand it should also not be silently accepted and give an incorrect result. The user should be alerted to the fact that the formula is invalid, preferably with an indication of what is wrong, and given a chance to correct the formula. | |
| Apr 22, 2024 at 5:42 | comment | added | sayanel | @Ben I agree, but I think I understand now that I'm working on part of the program that should always leave the app in valid state, and that why we should not throw. E.g. you don't risk crash Excel because the user entered an invalid formula. | |
| Apr 22, 2024 at 3:38 | answer | added | Flater | timeline score: 3 | |
| Apr 22, 2024 at 2:42 | comment | added | Ben | Re 'We are at risk of having a "Something went horribly wrong" message in production, and this should be avoided at all cost.' I must disagree strongly with the "at all cost" part. Something much worse than a "something went wrong" crash is ... something went wrong and the app didn't crash, it did the wrong thing. If you can avoid throwing because you can arrange to always leave a valid state, then that's good, 100% agree you should strive for this. If you avoid throwing by just leaving things in an invalid state and trusting all other code will handle it, then that's worse. | |
| Apr 21, 2024 at 23:00 | comment | added | Simon Geard | Consider this - the harder and earlier you fail when encountering invalid data, the more likely it is for the bug to actually be detected reliably and fixed. By not handling the situation as soon as possible -- and I count "crashing" as "handling" in this context -- you're allowing things to continue in a state where it's much more likely that you'll crash later instead, and it'll be much harder to figure out why. | |
| S Apr 21, 2024 at 17:12 | history | suggested | Bergi | CC BY-SA 4.0 |
clarify title
|
| Apr 21, 2024 at 15:54 | review | Suggested edits | |||
| S Apr 21, 2024 at 17:12 | |||||
| Apr 21, 2024 at 13:16 | comment | added | sayanel |
@njzk2 That is one solution. And I thought it was the best one, until a read @CortAmmon answer, and understood that my company chose to handle differently: object might have invalid state, all the object method should account for that (by checking the isValid() if (and only if) that's needed). Most passing around of the object do not care if it is valid or not, and when you really do something with the object you will check isValid before using it.
|
|
| Apr 21, 2024 at 12:10 | history | protected | gnat | ||
| Apr 21, 2024 at 11:55 | comment | added | njzk2 |
A better, more common rule is "A constructor should never give an invalid object". To follow this coding rules, public constructors should not be used, and a factory returning an Either<Object, Error> (or whatever the C++ equivalent is) sounds more appropriate.
|
|
| Apr 21, 2024 at 10:53 | comment | added | Carsten S | So no memory allocations in constructors? | |
| Apr 20, 2024 at 11:03 | comment | added | gaazkam | @BartvanIngenSchenau Initially I wanted to comment to respond to your comment, but the comment grew too long so I posted an answer instead - please see softwareengineering.stackexchange.com/a/452960/212639 | |
| Apr 20, 2024 at 11:02 | answer | added | gaazkam | timeline score: 4 | |
| Apr 20, 2024 at 8:37 | comment | added | Eric Lippert | I think you and perhaps your colleagues might have missed an important point that makes constructors special. If a constructor throws, the object is never destructed, so any work done by the constructor that needs to be undone is never undone. This is not the case in regular methods; regular methods destruct their locals when control returns normally or via an exception. | |
| Apr 20, 2024 at 7:27 | history | edited | sayanel | CC BY-SA 4.0 |
Added bold on the question itself
|
| S Apr 20, 2024 at 7:22 | history | suggested | CommunityBot | CC BY-SA 4.0 |
Fixed typo (“felling” → “feeling”), spelling and capitalization; improved punctuation (removed preceding spaces); tweaked wording/grammar.
|
| Apr 20, 2024 at 1:06 | comment | added | AndyG | I recommend reading into "smart constructor" patterns, which can be accomplished in C++... But you need to give up public constructors. "Parse, don't validate" is a great start. Careful, though, going down this hole will unlock a deep appreciation for some functional programming concepts. | |
| Apr 20, 2024 at 0:50 | answer | added | Kaia | timeline score: 11 | |
| Apr 19, 2024 at 21:45 | answer | added | GrandmasterB | timeline score: 3 | |
| Apr 19, 2024 at 21:01 | comment | added | Cort Ammon | @PhilipKendall Oh, my mistake. I see I misread cross-site and saw cross-post | |
| Apr 19, 2024 at 19:59 | review | Suggested edits | |||
| S Apr 20, 2024 at 7:22 | |||||
| Apr 19, 2024 at 19:35 | comment | added | Cort Ammon | @PhilipKendall I dont' think we can call this a crosspost. It's a different wording, different poster, and nearly 15 years apart. That question was asking if it was OK, and got uniformly "yes" answers. This question is asking why it isn't OK in the OP's setting, and is getting uniformly "no" answers. They're definitely related, but I woudln't call it a duplicate, much less a crosspost. | |
| Apr 19, 2024 at 19:29 | answer | added | gnasher729 | timeline score: 6 | |
| Apr 19, 2024 at 19:20 | answer | added | Cort Ammon | timeline score: 8 | |
| Apr 19, 2024 at 17:45 | answer | added | Ray | timeline score: 0 | |
| Apr 19, 2024 at 17:20 | history | became hot network question | |||
| Apr 19, 2024 at 13:44 | answer | added | Mehdi Charife | timeline score: -4 | |
| Apr 19, 2024 at 13:29 | comment | added | amon | It is possible to use C++ without exceptions, and sometimes necessary. Some compilers even offer a no-exceptions mode. Instead of throwing a recoverable error, the program will then abort() unrecoverably. Great for embedded! Awful for anything else. You cannot realistically opt out from exceptions because all the standard library classes like vector and string (but not iostreams) are built around exceptions. C++23 got std::expected for returning errors, but there's no chance of your team adopting this if they are holding on to 80s-era pre-standardization C++ practices. | |
| Apr 19, 2024 at 13:20 | answer | added | Joris Timmermans | timeline score: 5 | |
| Apr 19, 2024 at 12:12 | answer | added | IllusiveBrian | timeline score: 13 | |
| Apr 19, 2024 at 11:30 | review | Close votes | |||
| Apr 24, 2024 at 3:03 | |||||
| Apr 19, 2024 at 11:29 | answer | added | JonasH | timeline score: 51 | |
| Apr 19, 2024 at 11:14 | comment | added | Bart van Ingen Schenau |
@sayanel, the counter-argument for point 3 is that future programmers might forget to call isValid on an object that isn't valid and as a result cause a malfunction of the program. That malfunction could be less obvious but more devastating than an "oops" message to the user and it includes corrupting the user's critical data.
|
|
| Apr 19, 2024 at 11:10 | comment | added | gnat | Does this answer your question? Verifying Parameters in Constructor or Service | |
| Apr 19, 2024 at 10:53 | comment | added | Philip Kendall | @sayanel You can't never trigger the failsafe. But put in place good software engineering practices (code reviews, appropriate levels of testing, etc) and you can get to a point where it's triggered rarely enough not to be an issue. At the moment, your company's cure (no throw constructors) is arguably worse than the disease (sometimes triggering a failsafe). | |
| Apr 19, 2024 at 10:35 | comment | added | sayanel |
@PhilipKendall This is precisely after reading this SO question that I posted this : The accepted (and all others) answer say that throwing is the best practice, and init is not a good practice. Yet, I see it at my company. And I don't see a solution to the dilemma I ask: How to allow programmers to throw when needed, and ensure that we never trigger the ultimate "Something went wrong" fail-safe ? (factory seems to be a solution for constructor, but not in other cases)
|
|
| Apr 19, 2024 at 10:28 | history | edited | sayanel | CC BY-SA 4.0 |
Clarify point 1, and simplify example
|
| Apr 19, 2024 at 9:47 | comment | added | Philip Kendall | Cross-site sort of duplicate: Throwing exceptions from constructors | |
| Apr 19, 2024 at 9:41 | answer | added | Ccm | timeline score: 30 | |
| Apr 19, 2024 at 9:35 | answer | added | Caleth | timeline score: 25 | |
| Apr 19, 2024 at 9:30 | comment | added | Jiří Baum |
One phrase to look up for background reading would be "define errors out of existence"; particularly for the if (size < 0) {m_size = 0} example
|
|
| S Apr 19, 2024 at 9:19 | review | First questions | |||
| Apr 19, 2024 at 9:49 | |||||
| S Apr 19, 2024 at 9:19 | history | asked | sayanel | CC BY-SA 4.0 |