About use of specific error

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
47 messages Options
123
Reply | Threaded
Open this post in threaded view
|

Re: About use of specific error

Nicolas Cellier-3

Thanks Andreas for your different point of view.

So if i want these exceptions for my apps without breaking current behaviour for yours, then i need a default handler that quietly pass the exception and proceed with NaN or Inf. I do not figure yet how it would be implemented but that's something interesting to look at.

Nicolas


Andreas Raab:
nicolas cellier wrote:

> Lets return to arithmetic exceptions, I would really like to have them instead
> of silent NaNs/Inf. NaN should be a way of handling arithmetic exception, but
> not the preferred way. Anyone disagree ?

Completely. Personally, I've yet to find a place where a floating point
exceptions would be more useful than silent NaNs or Infs (btw, I'm not
arguing that this has to be true in your case, just that it is in mine ).

Cheers,
- Andreas





iFRANCE
exprimez-vous !


Reply | Threaded
Open this post in threaded view
|

Re: About use of specific error

Nicolas Cellier-3
In reply to this post by stéphane ducasse-2
Markus, of course, i agree that defensive programming is a must at least in critical places, and no i do not like the idea to have my data corrupted. In fact, defensive programming at low level is a prerequisite for doing optimistic programming at higher level.

Once you have put these exceptions at critical low levels, it is in some cases (i do not say all cases) far more comfortable to squeeze higher level precondition/postcondition tests and use exception handling instead. This is where i am speaking of programming style.

Lost of performance come not only from low level defense, but also from testing several times the same assertion in the call chain. Removing second half is not risky.

Nicolas

Markus Gaelli:

On Mar 17, 2006, at 3:57 AM, nicolas cellier wrote:

> However Markus, defensive programming is just a s tyle, not a bad
> style, but
> not the only one and not the most adequate in every case. There are
> many
> cases where optimistic programming is better, when failure cases
> are so
> unprobable that it would be a waste of time to repeatidly test costly
> assertions (also better regarding volume of code). Exceptions find
> their
> place here.

If you prefer corrupted data in your database over a a slower or
error throwing program (*) you could always switch off the assertions
in your production system later without any loss of performance:
http://www.whysmalltalk.com/articles/bykov/HitchHiker.htm

Implemented/ported by Romain Robbes:
http://lists.squeakfoundation.org/pipermail/squeak-dev/2004-March/
075327.html

Cheers,

Markus

(*) You might be in a project phase, where your project leader politically prefers bad data in the db than walkback screens in the
face of the end users.
At least I experienced such kind of a project once... ;-)



iFRANCE
exprimez-vous !


Reply | Threaded
Open this post in threaded view
|

Re: About use of specific error

Markus Gälli-3

On Mar 17, 2006, at 3:49 PM, [hidden email] wrote:

> Once you have put these exceptions at critical low levels, it is in  
> some cases (i do not say all cases) far more comfortable to squeeze  
> higher level precondition/postcondition tests and use exception  
> handling instead. This is where i am speaking of programming style.
>
> Lost of performance come not only from low level defense, but also  
> from testing several times the same assertion in the call chain.  
> Removing second half is not risky.

Ah...ok. Sure, I don't like checking the same stuff over and over again.
To quote myself from earlier in this thread:

>
> Example: I have a method to solve the quadratic equation f(x)=axx+bx+c
>
> Array >> #solveQuadraticEquation
> |a b c discriminant solutions |
> self precondition: [self size = 3 and: [self allSatisfy: [:each |  
> each isNumber]]].
> "Do I have to state here that the discriminant should be >= 0? I  
> do not think so."
> a:= self first.
> b:= self second.
> c:= self third.
> discriminant:=(b*b)-(4*a*c).
> solutions := Set new.
> solutions
> add:((0-b+discriminant sqrt)/(2*a));
> add:((0-b-discriminant sqrt)/(2*a)).
> ^solutions
>
> If the discriminant<0 the precondition of sqrt should fail. I do  
> not want to state that here also as I am lazy and as I have not  
> computed the discriminant in the beginning.
>

Meanwhile I came to the conclusion that a better style for above  
method would certainly be to always return a collection of solutions,  
in the case of a negative discriminant the collection should just be  
empty.
So it better looked like:

Array >> #solveQuadraticEquation
        |a b c discriminant solutions |
        self precondition: [self size = 3 and: [self allSatisfy: [:each |  
each isNumber]]].
        a:= self first.
        b:= self second.
        c:= self third.
        discriminant:=(b*b)-(4*a*c).
        discriminant < 0 ifTrue: [^#()].
        solutions := Set new.
        solutions
                add:((0-b+discriminant sqrt)/(2*a));
                add:((0-b-discriminant sqrt)/(2*a)).
        self postcondition: [
                (solutions size between: 1 and: 2)  and: [
                        solutions allSatisfy: [:each | ((a*each*each)+(b*each)+c) abs <=  
1.0e-10]]].
        ^solutions

A typical case for a predictable situation which can be handled  
perfectly well without having to deal with any exceptions.

I still fail to see why I would have to introduce exception handling  
at a higher level due to not stating the same assertion over and over  
again:
I did not understand your NaN example, could you elaborate on that or  
send another example?

Note that I added a post condition, so here come a

PRICE QUESTION: (the person answering to this one last gets a beer  
(or bounty?) next time we meet personally... ;-)

Would test cases for that method still need to state the expected  
outcome?
Sth. along the line of

ArrayTest >> testSolveQuadaticEquation
        self assert: (#(1 -4 4) solveQuadraticEquation asArray = #(2.0))
        (...)

Or would it be sufficient to just provide examples a la:

ArrayTest >> testSolveQuadaticEquation
        #(1 -4 4) solveQuadraticEquation.
        (...)

as the postcondition here is already basically an inverse function,  
and "nothing" should go wrong....
Any opinions on that?

Cheers,

Markus



Reply | Threaded
Open this post in threaded view
|

Re: Re: About use of specific error

Nicolas Cellier-3
In reply to this post by stéphane ducasse-2
Well, your example would fail with

#(1.0e300 5.0e300 6.0e300) solveQuadraticEquation

because of NaNs, but that would be detected in the post conditions,
though solution is obviously #(-3 -2).

And your postcondition might fail with

#(3.0e100 5.0e100 2.0e100) solveQuadraticEquation

because residual error might well get bigger than the 1.0e-10 tolerance, though accuracy on solutions would be quite good.

(sorry i have not a running image to assert what i say, but you will soon find similar example).

In the above case, you could catch this NaN and maybe retry with another algorithm that would first normalize first or last coefficient of you polynomial.
The example is not very good because we cannot figure why we need two algorithms here. But think of solving an eigenvalue problem or a Riccati equation, then we have several possible algorithms an could retry with matrix balancing or with another algorithm before giving up with an error notification.

Nicolas




Markus Gaelli:

On Mar 17, 2006, at 3:49 PM, [hidden email] wrote:

> Once you have put these exceptions at critical low levels, it is in
> some cases (i do not say all cases) far more comfortable to squeeze
> higher level precondition/postcondition tests and use exception
> handling instead. This is where i am speaking of programming style.
>
> Lost of performance come not only from low level defense, but also
> from testing several times the same assertion in the call chain.
> Removing second half is not risky.

Ah...ok. Sure, I don't like checking the same stuff over and over again.
To quote myself from earlier in this thread:
>
> Example: I have a method to solve the quadratic equation f(x)=axx+bx+c
>
> Array >> #solveQuadraticEquation
> |a b c discriminant solutions |
> self precondition: [self size = 3 and: [self allSatisfy: [:each |
> each isNumber]]].
> "Do I have to state here that the discriminant should be >= 0? I
> do not think so."
> a:= self first.
> b:= self second.
> c:= self third.
> discriminant:=(b*b)-(4*a*c).
> solutions := Set new.
> solutions
> add:((0-b+discriminant sqrt)/(2*a));
> add:((0-b-discriminant sqrt)/(2*a)).
> ^solutions
>
> If the discriminant<0 the precondition of sqrt should fail. I do
> not want to state that here also as I am lazy and as I have not
> computed the discriminant in the beginning.
>

Meanwhile I came to the conclusion tha t a better style for above
method would certainly be to always return a collection of solutions,
in the case of a negative discriminant the collection should just be
empty.
So it better looked like:

Array >> #solveQuadraticEquation
|a b c discriminant solutions |
self precondition: [self size = 3 and: [self allSatisfy: [:each |
each isNumber]]].
a:= self first.
b:= self second.
c:= self third.
discriminant:=(b*b)-(4*a*c).
discriminant < 0 ifTrue: [^#()].
solutions := Set new.
solutions
add:((0-b+discriminant sqrt)/(2*a));
add:((0-b-discriminant sqrt)/(2*a)).
self postcondition: [
(solutions size between: 1 and: 2) and: [
solutions allSatisfy: [:each | ((a*each*each)+(b*each)+c) abs <=
1.0e-10]]].
^solutions

A typical case for a predictable situation which can be handled
perfe ctly well without having to deal with any exceptions.

I still fail to see why I would have to introduce exception handling
at a higher level due to not stating the same assertion over and over
again:
I did not understand your NaN example, could you elaborate on that or
send another example?

Note that I added a post condition, so here come a

PRICE QUESTION: (the person answering to this one last gets a beer
(or bounty?) next time we meet personally... ;-)

Would test cases for that method still need to state the expected
outcome?
Sth. along the line of

ArrayTest >> testSolveQuadaticEquation
self assert: (#(1 -4 4) solveQuadraticEquation asArray = #(2.0))
(...)

Or would it be sufficient to just provide examples a la:

ArrayTest >> testSolveQuadaticEquation
#(1 -4 4) solveQuadraticEquation.
(...)

as the postcondition here is already basically an inverse function,
and "nothing" should go wrong....
Any opinions on that?

Cheers,

Markus






iFRANCE
exprimez-vous !


Reply | Threaded
Open this post in threaded view
|

Re: About use of specific error

Nicolas Cellier-3
In reply to this post by stéphane ducasse-2
Ah, i have forgotten another thing: your algorithm would almost work with Complex, except you should remove the discriminant < 0 test and change the precondition...

There, you can introduce exception for handling -2 sqrt, with two possibilities:
- return with empty collection
- return with complex solutions
This is just one possible style of programming (i would not say the best).
I think it would be better with a handler block as extra argument in this simple case.

Nicolas

Markus Gaelli:

On Mar 17, 2006, at 3:49 PM, [hidden email] wrote:

> Once you have put these exceptions at critical low levels, it is in
> some cases (i do not say all cases) far more comfortable to squeeze
> higher level precondition/postcondition tests and use exception
> handling instead. T his is where i am speaking of programming style.
>
> Lost of performance come not only from low level defense, but also
> from testing several times the same assertion in the call chain.
> Removing second half is not risky.

Ah...ok. Sure, I don't like checking the same stuff over and over again.
To quote myself from earlier in this thread:
>
> Example: I have a method to solve the quadratic equation f(x)=axx+bx+c
>
> Array >> #solveQuadraticEquation
> |a b c discriminant solutions |
> self precondition: [self size = 3 and: [self allSatisfy: [:each |
> each isNumber]]].
> "Do I have to state here that the discriminant should be >= 0? I
> do not think so."
> a:= self first.
> b:= self second.
> c:= self third.
> discriminant:=(b*b)-(4*a*c).
> solutions := Set new.< br /> > solutions
> add:((0-b+discriminant sqrt)/(2*a));
> add:((0-b-discriminant sqrt)/(2*a)).
> ^solutions
>
> If the discriminant<0 the precondition of sqrt should fail. I do
> not want to state that here also as I am lazy and as I have not
> computed the discriminant in the beginning.
>

Meanwhile I came to the conclusion that a better style for above
method would certainly be to always return a collection of solutions,
in the case of a negative discriminant the collection should just be
empty.
So it better looked like:

Array >> #solveQuadraticEquation
|a b c discriminant solutions |
self precondition: [self size = 3 and: [self allSatisfy: [:each |
each isNumber]]].
a:= self first.
b:= self second.
c:= self third.
discriminant:=(b*b)-(4*a*c).
discriminant < 0 ifTrue : [^#()].
solutions := Set new.
solutions
add:((0-b+discriminant sqrt)/(2*a));
add:((0-b-discriminant sqrt)/(2*a)).
self postcondition: [
(solutions size between: 1 and: 2) and: [
solutions allSatisfy: [:each | ((a*each*each)+(b*each)+c) abs <=
1.0e-10]]].
^solutions

A typical case for a predictable situation which can be handled
perfectly well without having to deal with any exceptions.

I still fail to see why I would have to introduce exception handling
at a higher level due to not stating the same assertion over and over
again:
I did not understand your NaN example, could you elaborate on that or
send another example?

Note that I added a post condition, so here come a

PRICE QUESTION: (the person answering to this one last gets a beer
(or bounty?) next time we meet personally... ;-)

Would tes t cases for that method still need to state the expected
outcome?
Sth. along the line of

ArrayTest >> testSolveQuadaticEquation
self assert: (#(1 -4 4) solveQuadraticEquation asArray = #(2.0))
(...)

Or would it be sufficient to just provide examples a la:

ArrayTest >> testSolveQuadaticEquation
#(1 -4 4) solveQuadraticEquation.
(...)

as the postcondition here is already basically an inverse function,
and "nothing" should go wrong....
Any opinions on that?

Cheers,

Markus






iFRANCE
exprimez-vous !


Reply | Threaded
Open this post in threaded view
|

Re: About use of specific error

Nicolas Cellier-3
In reply to this post by stéphane ducasse-2

What a fool am i, your example is already an eigenvalue problem : you are searching the eigenvalues of [0 , 1 ; -c/a , -b/a]. So the alternative algorithm when catching a Nan could be to ask lapack to solve that for you, for example with a Schur decomposition.

Nicolas


[hidden email]:

The example is not very good because we cannot figure why we need two algorithms here. But think of solving an eigenvalue problem or a Riccati equation, then we have several possible algorithms an could retry with matrix balancing or with another algorithm before giving up with an error notification.

Nicolas








<img border="0" align="left" src="http: //image.ifrance.com/mail/colibri.gif" /> iFRANCE
exprimez-vous !



iFRANCE
exprimez-vous !


Reply | Threaded
Open this post in threaded view
|

Re: About use of specific error

Markus Gälli-3
In reply to this post by Nicolas Cellier-3

On Mar 17, 2006, at 5:19 PM, [hidden email] wrote:

Well, your example would fail with

#(1.0e300 5.0e300 6.0e300) solveQuadraticEquation

because of NaNs, but that would be detected in the post conditions,
though solution is obviously #(-3 -2).
Indeed. I get:  a Set(NaN NaN)

And your postcondition might fail with

#(3.0e100 5.0e100 2.0e100) solveQuadraticEquation

Indeed. It does.
I should strengthen my precondition. I declare herewith that the whole thing only works Numbers but Floats
Who understands Floats (yeah, I know there is that FAQ, that I should frequently ask...) anyhow...;-)

because residual error might well get bigger than the 1.0e-10 tolerance, though accuracy on solutions would be quite good.

(sorry i have not a running image to assert what i say, but you will soon find similar example).

In the above case, you could catch this NaN and maybe retry with another algorithm that would first normalize first or last coefficient of you polynomial.
The example is not very good because we cannot figure why we need two algorithms here. But think of solving an eigenvalue problem or a Riccati equation, then we have several possible algorithms an could retry with matrix balancing or with another algorithm before giving up with an error notification.
Ok, thanks a lot for the nice counter examples above! :-)

Guess it boils down to the question if I want to compute something first, at least partially, only to find out, if "the whole thing" is computable like that at all.
If it is computable, I might have to repeat part of that computation. Using exception handling can avoid this duplication.
To check for an expected exception being thrown, I need to create a subclass in the exception hierarchy.

So it is a tradeoff between code duplication + performance hits between some "canCompute"/ "doCompute" combos on the one side - and the introduction of some new, quite empty, exception classes and exception handling code on the other side. Right?

Rephrasing it with some metaphor: 

In the optimistic way of developing you propose, you take a key that might fit into a door and try it hard, you will know at the end if it was ok and you are in. 
Otherwise you can remove the broken parts of the key (having pushed it too hard, parts of it got stuck in the lock...) with that special "remove my broken key out of that lock" exception-catching-tool you already have created for your toolbox, and then try the next one.
The pessimist would iterate over all keys and find the one that unlocks the door, take it out again(!) and then use it, being sure that it is the right one.

Thanks again for your patience, and feel invited for a beer ;-)

Markus



Nicolas




Markus Gaelli:

On Mar 17, 2006, at 3:49 PM, [hidden email] wrote:

> Once you have put these exceptions at critical low levels, it is in
> some cases (i do not say all cases) far more comfortable to squeeze
> higher level precondition/postcondition tests and use exception
> handling instead. This is where i am speaking of programming style.
>
> Lost of performance come not only from low level defense, but also
> from testing several times the same assertion in the call chain.
> Removing second half is not risky.

Ah...ok. Sure, I don't like checking the same stuff over and over again.
To quote myself from earlier in this thread:
>
> Example: I have a method to solve the quadratic equation f(x)=axx+bx+c
>
> Array >> #solveQuadraticEquation
> |a b c discriminant solutions |
> self precondition: [self size = 3 and: [self allSatisfy: [:each |
> each isNumber]]].
> "Do I have to state here that the discriminant should be >= 0? I
> do not think so."
> a:= self first.
> b:= self second.
> c:= self third.
> discriminant:=(b*b)-(4*a*c).
> solutions := Set new.
> solutions
> add:((0-b+discriminant sqrt)/(2*a));
> add:((0-b-discriminant sqrt)/(2*a)).
> ^solutions
>
> If the discriminant<0 the precondition of sqrt should fail. I do
> not want to state that here also as I am lazy and as I have not
> computed the discriminant in the beginning.
>

Meanwhile I came to the conclusion tha t a better style for above
method would certainly be to always return a collection of solutions,
in the case of a negative discriminant the collection should just be
empty.
So it better looked like:

Array >> #solveQuadraticEquation
|a b c discriminant solutions |
self precondition: [self size = 3 and: [self allSatisfy: [:each |
each isNumber]]].
a:= self first.
b:= self second.
c:= self third.
discriminant:=(b*b)-(4*a*c).
discriminant < 0 ifTrue: [^#()].
solutions := Set new.
solutions
add:((0-b+discriminant sqrt)/(2*a));
add:((0-b-discriminant sqrt)/(2*a)).
self postcondition: [
(solutions size between: 1 and: 2) and: [
solutions allSatisfy: [:each | ((a*each*each)+(b*each)+c) abs <=
1.0e-10]]].
^solutions

A typical case for a predictable situation which can be handled
perfe ctly well without having to deal with any exceptions.

I still fail to see why I would have to introduce exception handling
at a higher level due to not stating the same assertion over and over
again:
I did not understand your NaN example, could you elaborate on that or
send another example?

Note that I added a post condition, so here come a

PRICE QUESTION: (the person answering to this one last gets a beer
(or bounty?) next time we meet personally... ;-)

Would test cases for that method still need to state the expected
outcome?
Sth. along the line of

ArrayTest >> testSolveQuadaticEquation
self assert: (#(1 -4 4) solveQuadraticEquation asArray = #(2.0))
(...)

Or would it be sufficient to just provide examples a la:

ArrayTest >> testSolveQuadaticEquation
#(1 -4 4) solveQuadraticEquation.
(...)

as the postcondition here is already basically an inverse function,
and "nothing" should go wrong....
Any opinions on that?

Cheers,

Markus






iFRANCE
exprimez-vous !




123