Re: Какие у исключений проблемы?
От: D. Mon Великобритания http://thedeemon.livejournal.com
Дата: 05.11.14 03:03
Оценка: +1
Здравствуйте, vsb, Вы писали:


vsb>Какие есть серьёзные аргументы против исключений и за (извиняюсь за каламбур) возврат к кодам возврата?


Недавно как раз видел:

From the caller's perspective, language support for unchecked exceptions means something like:
"On any function call, instead of returning with a result with the expected type, a function may have the effect of running any destructors in scope, and then exiting the function to repeat the process, skipping all the actual instructions you wanted to execute or returning the type you were specified to return. Were you doing anything but calling functions in a linear sequence? I hope not, because the order in which they were called is going to affect your program's behavior now! Don't like it? Too bad!

So anyway, you never know whether this will happen or not. It's totally nondeterministic. You have no idea how often it happens, whether it's supposed to happen, if it can happen at all, anything. It's okay, though, because you can totally plan ahead and wrap it in a try block, and then if you have a "catch" block that accepts a type T, it might be called with data of that type, instead of returning from the function!
It might not, though. You don't really know. Make sure your code works if it does or doesn't.
But wait, if you have a finally clause after your try, that always runs, whether an exception was thrown or not! I mean, even if you return in the middle of the function, this block still runs! So that's pretty useful, no gotchas there! It's really nice, because it's the only part of this system where you can just write straightforward code!
(Just don't, like, call any functions or anything, because if you do that you might overwrite the exception type. Well, I guess you don't know if there's an exception type in scope or not. I guess just be, like, extra careful? Oh, and don't return in the finally block, that's bad news, that swallows the type too. Actually, don't do any nontrivial control flow at all. Okay, maybe it's not totally like normal code.)
Anyway, any time you call a function, make sure you keep all that in mind! And make sure that none of the above listed ways you can exit from your function can ever leave any of your state inconsistent in a way that violates the caller's expected invariants, because it would be pretty embarrassing if the caller decided to catch the exception at an inopportune moment! Oh, and make sure any destructors in scope also can't operate on their types while they're in an inconsistent state, or that could cause extreme terribleness!"
You have to think about this for every function call. And that's just the tip of the iceberg. I didn't even go into the various ways that exceptions screw you over in practice. Let's take Java, for example (which does not have destructors and does have checked exceptions, which are actually somewhat tolerable):

* Unchecked exceptions can actually happen basically anywhere. Not just inside functions. Because the Java specification raises exceptions for things like stack overflows, VM internal errors, allocation failure, etc. And Java also allocates everywhere.
* By the way, implicit conversions from unboxed to boxed primitives are function calls in this context and can thus trigger these errors.
* Thanks to the magic of inheritance, you generally can't actually enumerate all the possible error types (unless you are the that one Java developer who hates OOP and makes every class final. To that Java developer: I like you!). But that's okay, because most people just create a single error type and put 30 different exceptions under it, and just throw that from all their functions. If you're lucky.
* Also, thanks to Thread.stop, checked exceptions of any type can happen anywhere.
* Also, if you catch Throwable, you screw over anyone who was listening for a different type of exception.
* ALSO, InterruptedException has special semantics where when it's caught, it unsets the isInterrupted flag. Wisely, most people just make everything a RuntimeError or an IOException and wrap the old exception, so now you lose the flag and can't see the exception!
* Did I mention that the above is what Oracle recommends you do to use exceptions with try-with-resources?
* If you call a reflection API, you just get one exception type and get to unwrap it at runtime!

Every function call.
The "elegance" of (non-typesafe) exceptions is a myth. They're awful. You use them when you don't have an alternative.

 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.