On Sat, Nov 17, 2012 at 8:40 AM, Carlo E. Prelz <[email protected]> wrote: > Subject: Re: Question on exceptions > Date: Sat 17 Nov 12 12:47:06PM +0900 > > Quoting tamouse mailing lists ([email protected]): > >> Do you (or anyone else who'd like to chime in!) have a ... set of >> heuristics, maybe? .. that help you know when it's appropriate and >> when it's not?
> I will try to describe in words the fuzzy logic I follow. > > I do not often use exceptions. In more than seven years of using Ruby, > I have probably only subclassed Exception once or twice. Well, there are other uses of exceptions than defining your own. :-) One could even go as far as to say that you use exceptions if you use code that throws exceptions - even if there is no trace of catching exceptions in your code. That makes sense from a certain perspective because you rely on the fact that the code you use will raise exceptions if errors surface. > The Ruby interpreter's usage of exceptions is mostly limited to grave > events. What exactly is a "grave event"? > I try to mimic this usage in my raising practices. Basically, > exceptions should only indicate situations that have to be debugged > out: an exception should never indicate a special, but acceptable, > case. I beg to disagree. An IO error which surfaces is usually not something you will be tackling by debugging. You might be the invoker of a script who learns that way the the file name you passed on the command line was wrong. There may also be an network error because your WLAN lost connection spuriously etc. > I come from C (I still use C). Practice in C tends to be that your > procedures return non-zero in case of errors - the non-zero value > indicates the type of error. This can be cascaded: you check the > return value, and return the same if negative, and so on. But it can > certainly escalate to awkwardness, especially if at some level your > function has to return other data. What you describe neatly shows the major disadvantages of error handling via return type checking: - It is cumbersome (you need to check a lot return values). - It has to be done manually (i.e. you can forget it). - Propagation to invokers is tedious. - The error handling code is intermixed with regular code which makes the code harder to read. Of course, in C you do not have much choices since there are no exceptions in the language. > For me, the advantage of the exception mechanism is that it has its > own, separate distribution channel. If you do not catch an exception, > the program terminates, with VERY useful debugging data: the message > of the exception, and the backtrace. Absolutely. > When I encounter an exception, the catching option is not the > preferred one. If at all possible, I try to modify the code so that > the special case either does not happen, or is specifically handled, > in a programmatic way. Often you cannot do that. For example in the IO error case mentioned above the only thing you could do would be check the file for existence and readability before opening it. But since other processes have access to the file system as well that still does not give you 100% safety that the file is still there when you are going to open it. So just opening it and handling the exception (or just propagating it up the call stack) is the simpler option because the exception may come anyway. You end up with less code and a clearer structure. And in a way you avoid redundancy (duplicate checks for existence and accessibility). > If I catch an exception, I can do so at any of the steps of the > backtrace. Often it is useful to make use of the exception-raising > logic to get out of some of the levels of the call tree. Or put it differently: often it makes sense to handle an exception remote from to where it originated. > This iterative process is part and parcel of the testing phase that > all new code has to undergo. Every situation is different. If you > really care about the healthy operation of your code, every choice > should be tuned to the specific case. The process cannot be made > automatic. Automatic coding/debugging results in mediocre programs. Right, and if it was possible at all, we would be without jobs. :-) > In all cases, I would not use the exception mechanism in the example > that the original poster makes. Rather, the BankAccount#withdraw > method would return true (or possibly the new balance of the account) > if the withdraw method was successful, and false otherwise. Ruby has a > neat syntax for catching false/nil values: > > unless(account.withdraw(sum)) > ... # alternative account.withdraw(sum) or do_something_else > The condition of insufficient funds is maybe undesirable from the > point of view of the account holder, but it is a perfectly legitimate > situation; all mechanisms that handle withdrawals should foresee and > properly manage it. Withdrawals *can* fail. It should not be an > exception-al event from the point of view of the code. Unless for example the program cannot verify itself that funds are sufficient. It is not a too uncommon scenario to rely on database functionality (constraints) to ensure a negative balance is not reached. In this case the RDBMS driver's exception is necessary to learn of the violation because even if you do the check beforehand there can still be a transaction modifying the balance between the check and the withdraw (depending on concurrency model of the RDBMS of course, in Oracle and Postgres, where reads are not blocked by writes, you would either need explicit locking or work with the exception). > This is just an effort to put into words my craft. Every other > craftsman/woman will most probably follow different ways. I think your stress of context is very important. The downside is that it takes some time and experience to feel comfortable in all situations to decide on the proper way. Kind regards robert -- remember.guy do |as, often| as.you_can - without end http://blog.rubybestpractices.com/ -- You received this message because you are subscribed to the Google Groups ruby-talk-google group. To post to this group, send email to [email protected]. To unsubscribe from this group, send email to [email protected]. For more options, visit this group at https://groups.google.com/d/forum/ruby-talk-google?hl=en
