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. Phil --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@commons.apache.org For additional commands, e-mail: dev-h...@commons.apache.org