Le 23/01/2011 22:10, Phil Steitz a écrit : > On Sun, Jan 23, 2011 at 2:45 PM, Luc Maisonobe <[email protected]> wrote: >> Hi Phil, >> >> Le 23/01/2011 19:27, Phil Steitz a écrit : >>> Thanks for restarting the discussion of this topic, Gilles. >>> >>> Here is a first attempt at some principles for exceptions management >>> in [math], followed by an illustration using the ConvergenceException >>> case discussed in MATH-487. The principles are no doubt incomplete >>> and some may be wrong and/or not acceptable to the community. Lets >>> try to find consensus on a simple set of principles that we can agree >>> on and use as a guide in the 3.0 refactoring and new development. I >>> will update the Developers Guide with what we eventually agree to. >>> >>> 0) Exceptions generated by [math] are all unchecked. >>> >>> 1) All public methods advertise all exceptions that they can generate. >>> >>> 2) All exceptions inherit from the base class, MathRuntimeException >>> >>> 3) Whenever possible, methods fully specify parameter preconditions >>> required for successful activation. When preconditions are violated, >>> a MathIllegalArgumentException should be thrown. Subclasses of >>> MathIllegalArgumentException may be used to represent common parameter >>> contract violations (for example, NoBracketingException). Exception >>> messages must contain sufficient information on parameter values to >>> determine the exact precondition failure. >>> >>> 4) Exceptions generated by [math] make sense without knowing >>> implementation details other than those stated in the public API. For >>> example, a NoBracketingException makes sense thrown by a solver that >>> has an API precondition requiring that initial points bracket a root. >>> This exception does not make sense, however, thrown by an inverse >>> cumulative probability estimator. >>> >>> Together, 3) and 4) imply >>> >>> 5) MathIllegalArgumentException should only be thrown in situations >>> satisfying 3) - i.e., unless the preconditions can be exhaustively >>> provided so that what arguments are "illegal" can be specified fully >>> to the caller, different exceptions should be thrown on the event of >>> failure. For example, the exact domain of successful activation of a >>> solver or quadrature method may be impossible to specify because of >>> numerical properties of the method. If a solver fails to find a root >>> or a quadrature method fails to converge for a given set of >>> parameters, *unless those parameters violate the advertised >>> preconditions* it is not appropriate to throw >>> MathIllegalArgumentException. Domain-specific exceptions need to be >>> defined for these cases. For example, SingularMatrixException should >>> not inherit from MathIllegalArgumentException unless it is only thrown >>> in situations satisfying 3) . All current uses of >>> SingularMatrixException do satisfy 3), though the javadoc in some >>> cases needs a little cleanup to make it clear how singularity violates >>> the contract. My HO is that it would be better for >>> SingularMatrixException to not extend MathIllegalArgumentException, >>> substituting instead either just MathRuntimeException or a linear >>> domain-specific parent (shared by the other matrix exceptions). >>> >>> Now on to the ConvergenceException example. Many of our algorithms >>> amount to generating a sequence of values, hoping that the sequence >>> converges (really "gets Cauchy enough") and returning an estimate of >>> the limit of the sequence. Thus far, convergence is always in an >>> incomplete metric space and we usually have the extra-mathematical >>> issue to deal with that one form of divergence is becoming NaN. >>> Convergence failure happens when arguments are outside the >>> effectiveness range of the algorithm. It is often impossible to state >>> precisely in preconditions exactly what the conditions are on the >>> parameters that will lead to failed convergence. This is especially >>> true when the implementation code contains bugs :) >>> >>> Failed convergence manifests in three ways: a) maximum iterations >>> exceeded without meeting the convergence criteria b) iterates diverge >>> to an infinity an infinite result is not correct c) iterates "diverge >>> to NaN" and NaN is not correct. I suggest therefore, that we define: >>> >>> ConvergenceException extending MathIllegalStateException or even just >>> MathRuntimeException; >>> >>> MaxIterationsExceededException extends ConvergenceException, including >>> the max iterations as part of its state and message; >>> >>> IterationRangeException extends ConvergenceException, including the >>> out of range value encountered and what element of the sequence >>> attained the bad value (this allows values other than NaN or >>> infinities to count as "divergence"). >>> >>> We could also add InfiniteIterateException and NaNIterateException >>> extending IterationRangeException for these cases. >>> >>> I have often wanted to know how far out in the sequence one of the >>> values becomes infinite. Capturing this information in the exception >>> and including it in the message would be an improvement, IMO. The >>> fact that you *can* do this in the setup above is an illustration of >>> why I like domain-specific exceptions. >> >> Wow! That is a thorough analysis and a constructive one. >> >> I fully agree with you. I'm not sure that IterationRangeException is >> needed, but that is a minor point. > > I am curious why you see IterationRangeException as not needed when > MaxIterationsExceededException is, unless you think that the latter is > also unnecessary. These are really the two logical subclasses of > ConvergenceException. If we eliminate both of them, then we would > need an enum or something else to indicate the nature of the failed > convergence (iterates going out of range or max iterations exceeded).
Ah, OK I had something different in mind, my bad. Luc >> >> Concerning point 1), there are two ways to advertise the exception. >> Javadoc only, or Javadoc plus throws clause. I personnaly would prefer >> Javadoc plus throws clause > > +1 for both, with throws mandatory and javadoc also for all but > trivial cases. The conditions under which the exception may be thrown > *must* be fully specified in any case. If only mentioned in throws, > these must be pretty simple. > >> as it is simpler to make sure we didn't >> forget anything (using the trick of temporarily changing the base class >> for MathRuntimeException and look at compiler errors). > > Now *that* is a good trick. Thanks for point it out :) > > Phil >> >> Big +1 >> >> Thanks, >> Luc >> >>> >>> Phil >>> >>> --------------------------------------------------------------------- >>> To unsubscribe, e-mail: [email protected] >>> For additional commands, e-mail: [email protected] >>> >> >> >> --------------------------------------------------------------------- >> To unsubscribe, e-mail: [email protected] >> For additional commands, e-mail: [email protected] >> >> > > --------------------------------------------------------------------- > To unsubscribe, e-mail: [email protected] > For additional commands, e-mail: [email protected] > --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
