commons-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Phil Steitz <phil.ste...@gmail.com>
Subject Re: [math] last steps before releasing 2.2 ?
Date Sun, 30 Jan 2011 15:20:33 GMT

On Jan 28, 2011, at 11:31 PM, Gilles Sadowski wrote:

> Hello.
> 
>>>>>>> OK.  But now that we have detected an "aroma" around unilaterally
>>>>>>> making UnivariateRealFunction throw Math*User*Exception, I wonder
if
>>>>>>> there is a way to introduce an unchecked parent that gets us
out of
>>>>>>> this. We may want to reserve the right to do this in 3.0, so
the "head
>>>>>>> start" in 2.2 might be a head start to nowhere, unless we find
a way
>>>>>>> to fix it in 2.2 (or you convince us that the current setup is
an OK
>>>>>>> long-term solution).
>>>>>> 
>>>>>> I don't understand what you mean.
>>>>>> "MathUserException" is unchecked so it has no consequence that it
is in a
>>>>>> "throws" clause.
>>>>>> Or do you want to not remove FunctionEvaluationException from the
"throws"
>>>>>> clause (because it is not a backward-compatible change)?
>>>>>> 
>>>>> The "aroma" I was referring to is that MathUserException is not,
>>>>> strictly speaking a suitable replacement for
>>>>> FunctionEvaluationException.  The intent as described in the javadoc
>>>>> for MathUserException is that it allows exceptions in user-defined
>>>>> functions to be propagated through [math] API layers (an excellent
>>>>> idea, IMO).
>>> 
>>> I somewhat agreed on this point, because it doesn't hurt, although, as said
>>> earlier, I really doubt that we can set a standard. [Anyway IMO it's fine
>>> that users create whatever exception they like.]
>>> 
>>>>> The problem is that FunctionEvaluationException is
>>>>> broader - it could apply to non-user-defined functions, as in the
>>>>> interpolation code that Luc pointed out.
>>> 
>>> I mentioned that the "interpolate" method creates an object that implements
>>> the "UnivariateRealFunction" interface.
>>> Unless I'm missing something, the "problem" you mention does not exist. The
>>> actual problem was the very _existence_ of "FunctionEvaluationException": A
>>> class that was almost never actually instantiated within CM (and in the
>>> places where it was, it was the wrong thing to do). [And the fact that is
>>> was a chacked exception made things worse: try/catch all the way up for
>>> something that never happens! That's why I argued that it be removed.]
>> 
>> I understand your point, 
> 
> I'm not so sure. Maybe I don't explain clearly.
> 
>> but I disagree with it.  We are back to a
>> basic principle of API design that we need to settle.  My view is that
>> FunctionEvaluationException absolutely makes sense at the API boundary
>> of UnivariateRealFunction#value.  It is the right abstraction at that
>> level - it says that an exception occurred evaluating a function.
> 
> It is not because it doesn't convey any non-obvious information.
> How is this
> ---
>  try {
>    f.value(x);
>  } catch (FunctionEvaluationException e) {
>    console.warn(e);
>  }
> ---
> more informative than this
> ---
>  try {
>    f.value(x);   
>  } catch (MathRuntimeException e) { 
>    console.warn(e);
>  }
> ---
> ? [I mean, you "try" to call a method that will _evaluate_ the function, so
> that, when you "catch" something, it's, quite obviously, because the
> evaluation failed.]
> 
> Following your rationale, one would have to create one exception for each
> possible action (method). You have an API that would look like
> 
> * "value" can raise an "EvaluationException"
> * "interpolate" can raise an "InterpolationException"
> * "solve" can raise a "SolveException"
> * "integrate" can raise an "IntegrationException"
> * "optimize" can raise an "OptimizationEception"
> etc, etc.
> 
> If you want to talk in terms of boundaries, I think that these abstractions
> are on the other side of the CM boundary, i.e. they are useful to users of
> CM within their own code.
> On this issue, we have been in disagreement for a long time; I'm pretty sure
> that this is because both Luc and you are heavy users of CM and you cannot
> separate your role of developer of CM from the role of developer of
> applications-that-use-CM.
> 
This is sort of a core principle of how OSS in general and Commons in particular works - developers
"scratch itches" based on their practical needs and the software benefits tremendously from
that.  What results is software that meets the practical needs of users.  When developing
reusable components - especially OSS components - we absolutely must put the perspective of
the library user first.  This is not something that we can argue about.  It is how we work
@apache and in Commons.

Our exceptions design really needs to meet the needs of both [math] developers and [math]
users.  A well-structured hierarchy that expresses both high-level (e.g., FunctionEvaluationException,
ConvergenceException) and low-level (e.g. NonSymmetricMatrixException) will make the lives
of both users and [math] developers easier.   Other Commons components and successful libraries
succeed in meeting the needs of both end users and internal developers and we need to do the
same.  Some "comparative shopping" might help us here and maybe cajoling some other Commons
developers with experience maintaining libraries into jumping in here might help us.  One
thing we always need to keep in mind is that the public API is our contract to our users -
everything we expose we are telling them they can use and depend on.  

I don't follow the example you presented.  I was more thinking about situations where as an
external user or internal developer I might pass a function an argument outside of its domain
(and I might know this in advance).  This is a basic situation, similar to failed convergence.
 One could encounter it, for example, when computing the value of the objective function for
the start value passed to a solver.  If the start value is outside the domain of the function,
then the UnivariateRealFunction should throw a FunctionEvaluationException.  We can discuss
further how FunctionEvaluationException might be refined, but ArgumentOutsideDomain makes
sense in this case.  Note that this is *much better* than something like "NumberTooLarge"
or other disjointed low-level exception from the standpoint of the caller (the actor that
*really counts* - whether this is internal [math] code or user code).  The code that passes
the bad initial value could well be able to recover by perturbing whatever algorithm it is
using to select the initial value. 

You make a good point about us needing to be careful not to go overboard with too many overly-specific
exceptions.  I agree strongly that introducing a new exception for every algorithm or method
in [math] is not what we want to do.  Similar to data structures (I think we have done a good
job avoiding introducing abstract entities until we really have need for them), we need to
be parsimonious and build the hierarchy based on concepts with wide application.  In my opinion,
FunctionEvaluationException and ConvergenceException are examples of these.  I agree that
things like "InterpolationException" are not;  though things like SingularMatrixException
are.  The latter is an excellent example of a broadly useful exception like FunctionEvaluationException.
 Just as I may know that it is possible in my user or internal [math] code that I might pass
an argument to a function that is outside its domain or that my numerical implementation of
the function will choke on, I might know in other situations that a matrix may become numerically
singular.  In each case a) being able to catch the exception and b) seeing the meaningful
exception in the stack trace are useful to me (with either hat on).


 


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@commons.apache.org
For additional commands, e-mail: dev-help@commons.apache.org


Mime
View raw message