Path: news.daimi.aau.dk!news.uni-c.dk!newsfeed.sunet.se!news00.sunet.se!sunic!news.sprintlink.net!newsfeed.internetmci.com!in2.uu.net!news.cais.net!news.cais.com!news From: Eric Vought Newsgroups: comp.object,comp.lang.eiffel,comp.lang.c++,comp.lang.beta,comp.lang.java,comp.lang.sather Subject: Re: What Should An Exception Handling Do? -- Clarification of rules Date: Tue, 02 Apr 1996 16:03:27 -0500 Organization: Capital Area Internet Service info@cais.com 703-448-4470 Lines: 131 Message-ID: <3161961F.1FEE8722@ids2.idsonline.com> References: <4irn11$7ln@mimas.brunel.ac.uk> <4j03p4$fbt@hoho.quake.net> <4jcf89$2k9@crc-news.doc.ca> <4jdv0p$lnr@dscomsa.desy.de> NNTP-Posting-Host: ip158.idsonline.com Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit X-Mailer: Mozilla 2.01 (X11; I; Linux 1.2.13 i486) Xref: news.daimi.aau.dk comp.object:53645 comp.lang.eiffel:22637 comp.lang.c++:176411 comp.lang.beta:10702 comp.lang.java:30914 comp.lang.sather:12393 > I don't know, though, if the above is a real-world example. Most > people don't seem to program that way. But it is an example, of > what *I* like to be able to do. It requires: > > * The exception handler must have both access to the context of the > caller as well to that of the callee. In particular, the callee's > data must still exist, when the exception handler is reached. > * The exception handler must be able to decide, where to resume the > execution of the callee, whether at the throw point, at some > designated breakpoint, or not at all. > > I don't see, how C++'s throw/catch/try scheme is able to handle this > general case. This is one of the reasons, why I dislike C++, and prefer > BETA. But this is a question of taste, not a question of reason. Maybe I'm misunderstanding you, but I see several problems with this line of thought. First of all, the point of exception handling as I see it: Exception handling is a way that the author of library routines that are used across many applications can defer decisions on how to handle errors to the caller of the routine. For instance, if a file cannot be accessed, rather than aborting or printing an error message to standard error, or automatically trying another file, the application designer, who has knowledge about what the system is trying to do and what recourses are available can catch the exception and attempt to deal with it. This may entail informaing the user, modifying the parameters of the mthod call and retrying, or other possibilities. In any case, there are several things to be considered here: 1) The library author has no knowledge about implementations that may use the library routine(s). Therefore, the library author cannot anticipate how the exception might be dealt with outside of the library routines themselves. 2) The implementor should not have any knowledge about the *implementation* of the library routines. Even if the implementor has such information, using it can be disasterous in the case of changes in the library implementation over time. 3) Exceptions flag *exceptional* circumstances. That is, circumstances that are not easily anticipated and do not occur often. Item one seems to cause problems with resumption semantics because the library has no idea what a user might want to do in a error handling routine, and therefore has no idea if the state of the object is still consistent when the handler returns to the point of the throw. In other words, lets say that an object invariant is modified in the course of a method call. An exception is thrown, not terminating the method, and not executing a finally block or equivalent. That means that the object is in an inconsistent state when the error code executes and may or may not be (depending on what further methods are called) when the method resumes. As a comparison, termination semantics allow the method to clean up, restoring invariantes before the error code executes. When the code is reentered, through a retry of the method call, the code can then be assured that it is in a known and consistent state. Item two means that the error code cannot know about the implementation of the method, and therefore cannot know about what invariantes may or may not be temporarily violated within its context. Even if it did, unless the code were able to be run with private access to the object (a *very* bad idea), it could not make the object consistent before continuing. Even worse, if the implementation of the method were ever to change, all error code that took its implementation into account or accessed its state would break. Item three means that common or easily anticipated conditions should not use exception handling. For one thing, exception handling is slow when compared to a method call or inlined code. Something like a CD skipping (and thus retrieving the next pice from a buffer) should not be handled by exceptions for two reasons: 1) it is a very common occurence (in a portable CD-Player anyway) and therefore should be optimized, and 2) it can be resolved in the context of the method and does not require the execution path to change. A simple if statement based on a method return value will suffice here. IMHO, situations that require resumption symantics can be handled much more cleanly in other ways, without violating OOP principles of encapsulations. If the library designer anticipates that a user would want to supply a error recovery routine in a resumption situation, then a registered callback or interfaced object can be supplied: interface SpecialAlternateBuffer { //... } // SpecialAlternateBuffer class A { SpecialAlternateBuffer sab; A(SpecialAlternateBuffer sab) { // initialize ... } // A String TrySomethingThatWontWork(String location) { String returnVal = RetrieveFrom(location); if (returnVal = null) { return sab.GetFromElsewhere(interestingData); } else { return returnVal(); } } // TrySomethingThatWontWork //... } // A This is a simplistic example, but it illustrates that an error is handled from the point where on might be tempted to throw an exception and all data that the error handling code has access to is explicitly given to it. Neither class A, nor the recovery code needs any information that it shouldn't have access to. Because the recovery code is called explicitly from a particular point, the method writer can ensure that the object is in a consistent state before the call. Obviouslt, in situations where the library author has even less of an idea of how the error might be handled, an exception should be thrown, providing a finally block for cleanup, and the method should be reentered after having fixed the location or specifying an alternative location. Personally, I dislike the fact that Java does not allow method references, as they would be ideal in this situation. How hard would it be for them to implement references to static methods?