commons-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Luc Maisonobe <>
Subject Re: [Math] Exception handling (again)
Date Sun, 23 Jan 2011 21:18:18 GMT
Le 23/01/2011 22:10, Phil Steitz a écrit :
> On Sun, Jan 23, 2011 at 2:45 PM, Luc Maisonobe <> 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.


>> 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:
>>> For additional commands, e-mail:
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail:
>> For additional commands, e-mail:
> ---------------------------------------------------------------------
> To unsubscribe, e-mail:
> For additional commands, e-mail:

To unsubscribe, e-mail:
For additional commands, e-mail:

View raw message