5 ms·
> Has anyone seen properly-RAII-ed code where exceptions still have drawbacks? The drawback is "properly-RAII-ed code". It's hard to write because where you wr
by jstimpfle 9y ago
> Has anyone seen properly-RAII-ed code where exceptions still have drawbacks?
The drawback is "properly-RAII-ed code". It's hard to write because where you write the RAIIed classes you don't have the context of the place / places where it's used. It's extremely hard to read and step through with a debugger - because control flow is all over the place. I don't want to write classes instead of simple regular control flow.
And regarding standard control flow code, I've never seen a code base that handles exceptions correctly / elegantly / in a disciplined way. The only way to deal with exceptions is handling them immediately, i.e.
try:
f = open(filepath)
except FileNotFoundError:
handle_file_not_found()
To be honest I prefer C-style return code handling. It would be only 2 or 3 lines instead of these 4, and no additional indentation, and no additional value return mechanism. The only cost of C-style handling vs exceptions is duplicating a few library functions: Need to offer interfaces that die and ones that allow handling the error. And there's the possibility of forgetting to handle the error (if the caller considers it an error, after all) once in a long while. But you have that problem with exceptions, too...
In other words, exceptions are good for writing sloppy code (I like writing Python scripts, but I rarely handle exceptions), and very bad for serious code bases.
- falcolas 9y agoAt least with exceptions, “forgetting to handle the error” results in a predictable bubbling of the exception, as opposed to continuing with an unknown state.
- bbatha 9y agoThat’s already a property of rust errors. If a function errors you can’t use its return value until you handle the error some way either explicitly, forward it with the ? operator, or unwrap it indicating an unrecoverable error.
- falcolas 9y agoThe parent was referring to C style error handling, not Rust.
- ensiferum 9y agoLol. All so wrong.
- zaphar 9y agoIf you think it's all wrong then explain why. If all you want to do is signal in-group status or cargo-cult thinking then you'll get downvoted to oblivion. Hacker News has a pretty strongly developed immune response to this sort of comment.
- anacrolix 9y agoThe flaw is in the language syntax. With a language that allows a lightweight, more general manipulation of flow you just get open filepath `catch` handle_file_not_found >>= use_file_handle handle_file_not_found :: FileNotFoundError -> IO a use_file_handle :: FileHandle -> IO a
- jstimpfle 9y agoSure, I know Haskell too, and that code above is a mouthful... I'm undecided what is worse in terms of "control flow is all over the code base" and "code is hard to understand" - C++ RAII or Haskell error handling. Moreover the latter comes in a thousand incompatible flavours. Have fun writing Monad transformers :-). It's next to impossible to engineer a robust and readable/maintable application this way (besides simply dying on errors).
- xamuel 9y agoPeople misuse exceptions. They use them as control-flow, like another form of "if...then", and as you point out, they're terrible for that. The proper way to use exceptions is when you want behavior that bubbles up. So if you do x=f(g(h(x))) and h(x) fails because the user didn't configure something, you only need the config-checking logic in h, not in g or f. This use-case is quite rare though, and overall not worth the extra language complexity.
- ZirconiumX 9y agoIf you don't mind me asking, what do you think of Go-style error handling where there are multiple return types: one exclusively for errors and however many for actual results. Is this better to your eyes?
- jstimpfle 9y agoI think there is not much difference. I used that approach myself once when writing a simple parser in python. I think it lacks some elegance, but it may be better than out-arguments (pointer argument to return value). On the other hand, the two-variables handling has the disadvantage that the "real" return variable is always (over)written, also in case of error. I think there is one underused error handling mechanism: "asynchronous error handling" where you have to to ask for errors explicitly. Like in the OpenGL API, for example. It might be the best choice where there is a lot of communication between largely isolates states. So that could be one answer: If possible design the API in such a way that functions that can have expected errors [1] do not return values that only make sense if there was no error. Because this means that control flow gets very irregular on the calling side. Such a design could be hard to do though, I don't know. The other answer could be: Don't have errors that you don't know how to handle. Unless you write very low-level code, like a library (which means you probably want to delegate the handling), just die on errors that you don't know how to handle. Make the die() call a best-effort cleanup routine if possible, and keep the important to-be-cleaned up state as global as possible (NOT on the call stack), to support such a cleanup routine. [1] I hate the vagueness of that term, but take it to mean "no statically obvious wrong usage by the caller", like passing in made-up or corrupted values
- Too 9y agoCute example but what exactly does your handle_file_not_found() function do? Isn't it the caller further up the stack that knows best what to do? Assuming your example code is inside library_function_foo() and I'm a web server calling into library_function_foo() i know i should return http code 500 if "anything" throws an exception, if i reuse library_function_foo() in another command-line client project i might want it to print the error message to stdout instead.
- jstimpfle 9y ago> Isn't it the caller further up the stack that knows best what to do? Often yes (one of the exceptions being a simple die() routine that cleans up only global state). It's just pseudocode, and in real code you will often not call any functions in the exception handling block.
- toopsss 9y agoWell there are many cases where you don’t have to handle them immediately but the key is that your set of exceptions has to be restricted. Some random filenotfound is not very helpful it has to be converted. This of course is because something like file open failure isn’t really long range throwing exceptionable by itself. Python is special in that they took the simple approach all errors are exceptions which leads to a lot of try catch blocks. This keeps the design very simple which is good for python I think. For python this is really more a syntactic wart I would argue. Everything is an exception, fine I say (for python). It just sucks there isn’t a cleaner one line syntax for translating that typical example you gave.