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

Reply via email to