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
|

About use of specific error

stéphane ducasse-2
Hi all

I asked students of my lecture to write SUnit tests for some  
collections and I noticed that in Squeak
the collection library do not use specific exception but instead use  
error:.
The consequence is that it can be tedious to capture only specific  
error. I was wondering what is the
general feeling about this state. In VW they have various exception  
that can be trapped more specifically.

Stef

Reply | Threaded
Open this post in threaded view
|

Re: About use of specific error

Markus Gälli-3
Hi Stef,

let's have a look a the following example:

Intervall >> remove: anElement
        self error: 'elements cannot be removed from an Interval'

What do you mean with "trapped more specifically"?

I would claim that almost all (happy for any counter example) uses of  
"self error:" are indicating that some (maybe implicit) precondition  
fails.
Being radical I would say in above situation the precondition just  
fails always, meaning that this method would never make sense to be  
called on Intervals.

Using traits we shouldn't need the strange idiom to overwrite  
template or other superclass methods, that do not work in special  
subclasses, any more.
(It would be really tedious to enumerate all methods on all classes  
which do not work... ;-)

If the error string is telling me why the precondition fails, good.  
Why would I want to bother with different kinds of exceptions here?

By the way, I call a test, which tests the failing of a precondition,  
"pessimistic method example", but I am still open for a better name.
People did not like the name "counter example" or "negative example",  
though I still would prefer one of these names and I am about to  
rename...

Cheers,

Markus

On Mar 1, 2006, at 10:29 PM, stéphane ducasse wrote:

> Hi all
>
> I asked students of my lecture to write SUnit tests for some  
> collections and I noticed that in Squeak
> the collection library do not use specific exception but instead  
> use error:.
> The consequence is that it can be tedious to capture only specific  
> error. I was wondering what is the
> general feeling about this state. In VW they have various exception  
> that can be trapped more specifically.
>
> Stef
>


Reply | Threaded
Open this post in threaded view
|

Re: About use of specific error

Boris.Gaertner
In reply to this post by stéphane ducasse-2

stéphane ducasse <[hidden email]> wrote:

 
> Hi all
>
> I asked students of my lecture to write SUnit tests for some  
> collections and I noticed that in Squeak
> the collection library do not use specific exception but instead use  
> error:.
In a Squeak3.8-5989 basic image we have 850 senders of
error:


> The consequence is that it can be tedious to capture only specific  
> error.
Yes, it is often necessary to ask an exception for its message
text to understand what happened. Checking the message texts
is of course a bit risky, they can be changed at any time,
they may be localized and so on.

> I was wondering what is the
> general feeling about this state. In VW they have various exception  
> that can be trapped more specifically.
>

The collection relevant senders of error: are
coded in these methods:

Object>>errorSubscriptBounds:
Object>>errorNonIntegerIndex

Collection>>errorEmptyCollection
Collection>>errorNotKeyed
Dictionary>>errorKeyNotFound
Dictionary>>errorValueNotFound
SequenceableCollection>>checkedAt:
SequenceableCollection>>errorFirstObject:
SequenceableCollection>>errorLastObject:
SequenceableCollection>>errorOutOfBounds
Set>>add:

SequenceableCollection>>with:do:
SequenceableCollection>>with:collect:

Using specialized exceptions is attractive, but
it is not easy to find a good exception
hierarchy. What do you think about this
hierarchy for collection related errors?

Error
  CollectionAccessError
    IndexOutOfBoundsError
    KeyNotFoundError
    EmptyCollectionError

This would give you the possibility to write
handler like:

 [collection at: item]
   on: CollectionAccessError
   do:
     [:exception |
        " exception class tells you more about
          the nature of the error "
     ].


Apart form the problem of finding a good
hierarchy, we have to ask ourselves how many
exception classes we want to have. For
teaching purposes, it is a good idea to
implement a stack with a FullStackError
and an EmptyStackError and a common
superclass  StackError, but is it really
necessary to have tenths or hundreds of
specialized error classes in a general purpose
image?

I think I would like to have specialized exceptions
for collections, but perhaps this is something one
should try to find out whether there are hidden
disadvantages.

Greetings,
Boris

Reply | Threaded
Open this post in threaded view
|

Re: About use of specific error

stéphane ducasse-2
In reply to this post by Markus Gälli-3

On 2 mars 06, at 11:12, Markus Gaelli wrote:

> Hi Stef,
>
> let's have a look a the following example:
>
> Intervall >> remove: anElement
> self error: 'elements cannot be removed from an Interval'
>
> What do you mean with "trapped more specifically"?

Not for this one
        but
                IndexNotFoundError
                KeyNotFoundError
                SubscriptOutOfBoundsError

> I would claim that almost all (happy for any counter example) uses  
> of "self error:" are indicating that some (maybe implicit)  
> precondition fails.
> Being radical I would say in above situation the precondition just  
> fails always, meaning that this method would never make sense to be  
> called on Intervals.

But I'm not talking about that in particular.

Dictionary>>at: key
        "Answer the value associated with the key."

        ^ self at: key ifAbsent: [self errorKeyNotFound]

errorKeyNotFound

        self error: 'key not found'

errorValueNotFound

        self error: 'value not found'



> Using traits we shouldn't need the strange idiom to overwrite  
> template or other superclass methods, that do not work in special  
> subclasses, any more.
> (It would be really tedious to enumerate all methods on all classes  
> which do not work... ;-)

Sure but this was not my point.

> If the error string is telling me why the precondition fails, good.  
> Why would I want to bother with different kinds of exceptions here?
>
> By the way, I call a test, which tests the failing of a  
> precondition, "pessimistic method example", but I am still open for  
> a better name.
> People did not like the name "counter example" or "negative  
> example", though I still would prefer one of these names and I am  
> about to rename...
>
> Cheers,
>
> Markus
>
> On Mar 1, 2006, at 10:29 PM, stéphane ducasse wrote:
>
>> Hi all
>>
>> I asked students of my lecture to write SUnit tests for some  
>> collections and I noticed that in Squeak
>> the collection library do not use specific exception but instead  
>> use error:.
>> The consequence is that it can be tedious to capture only specific  
>> error. I was wondering what is the
>> general feeling about this state. In VW they have various  
>> exception that can be trapped more specifically.
>>
>> Stef
>>
>
>
>


Reply | Threaded
Open this post in threaded view
|

Re: About use of specific error

Markus Gälli-3
In reply to this post by Boris.Gaertner
Hi Boris,

>> The consequence is that it can be tedious to capture only specific
>> error.
> Yes, it is often necessary to ask an exception for its message
> text to understand what happened.

Could you give an example please?

I am still not convinced that the idiom of "first (possibly) hitting  
the wall, and then asking for the door" is a good one to teach  
students programming.
I think it would be better to teach students a _defensive_ way of  
programming, that is to ask first, if everything is ok, using some  
boolean queries and if these queries do not exist, let them write  
these queries and _not_ exception hierarchies.

Exceptions are a way of goto programming and can become quite hairy  
to use. I am glad to be in sync here with Andrew Thomas and Dave Hunt  
in their nice book about the pragmatic programmer.
They write something like using exceptions should be actually saved  
for situations, the developer cannot predict, such as external io-
failures etc.

I am all for letting the programmers know which precondition they  
violated calling a method, but only for debugging their code, and not  
for using that info _in_ their code.

I am aware that there is a slight performance penalty to ask if  
everything is ok first all the times, also when everything _is_ ok.
But I'd teach above idiom more as the exception than as the  
rule... ;-) -- if at all.

Cheers,

Markus


Reply | Threaded
Open this post in threaded view
|

Re: About use of specific error

stéphane ducasse-2
In reply to this post by Boris.Gaertner
>> The consequence is that it can be tedious to capture only specific
>> error.
> Yes, it is often necessary to ask an exception for its message
> text to understand what happened. Checking the message texts
> is of course a bit risky, they can be changed at any time,
> they may be localized and so on.

Indeed

>
>> I was wondering what is the
>> general feeling about this state. In VW they have various exception
>> that can be trapped more specifically.
>>
>
> The collection relevant senders of error: are
> coded in these methods:
>
> Object>>errorSubscriptBounds:
> Object>>errorNonIntegerIndex
>
> Collection>>errorEmptyCollection
> Collection>>errorNotKeyed
> Dictionary>>errorKeyNotFound
> Dictionary>>errorValueNotFound
> SequenceableCollection>>checkedAt:
> SequenceableCollection>>errorFirstObject:
> SequenceableCollection>>errorLastObject:
> SequenceableCollection>>errorOutOfBounds
> Set>>add:
>
> SequenceableCollection>>with:do:
> SequenceableCollection>>with:collect:
>
> Using specialized exceptions is attractive, but
> it is not easy to find a good exception
> hierarchy. What do you think about this
> hierarchy for collection related errors?
>
> Error
>   CollectionAccessError
>     IndexOutOfBoundsError
>     KeyNotFoundError
>     EmptyCollectionError
>
> This would give you the possibility to write
> handler like:
>
>  [collection at: item]
>    on: CollectionAccessError
>    do:
>      [:exception |
>         " exception class tells you more about
>           the nature of the error "
>      ].
>
>
> Apart form the problem of finding a good
> hierarchy,

Which is not easy

> we have to ask ourselves how many
> exception classes we want to have. For
> teaching purposes, it is a good idea to
> implement a stack with a FullStackError
> and an EmptyStackError and a common
> superclass  StackError, but is it really
> necessary to have tenths or hundreds of
> specialized error classes in a general purpose
> image?

Exactly. I would be against it.
I think that exception are often a Java plague :)
Still I was thinking that thinking about that could be interesting.

> I think I would like to have specialized exceptions
> for collections, but perhaps this is something one
> should try to find out whether there are hidden
> disadvantages.

Thanks for the email because it shows that we are in sync.

Stef

>
> Greetings,
> Boris
>


Reply | Threaded
Open this post in threaded view
|

Re: About use of specific error

stéphane ducasse-2
In reply to this post by Markus Gälli-3

On 2 mars 06, at 13:49, Markus Gaelli wrote:

> Hi Boris,
>
>>> The consequence is that it can be tedious to capture only specific
>>> error.
>> Yes, it is often necessary to ask an exception for its message
>> text to understand what happened.
>
> Could you give an example please?
>
> I am still not convinced that the idiom of "first (possibly)  
> hitting the wall, and then asking for the door" is a good one to  
> teach students programming.

I was not talking about teaching anything.
I just asked them to write tests and I was surprised that I have to  
catch always Error and not more precise Exception.


> I think it would be better to teach students a _defensive_ way of  
> programming, that is to ask first, if everything is ok, using some  
> boolean queries and if these queries do not exist, let them write  
> these queries and _not_ exception hierarchies.
>
> Exceptions are a way of goto programming and can become quite hairy  
> to use. I am glad to be in sync here with Andrew Thomas and Dave  
> Hunt in their nice book about the pragmatic programmer.
> They write something like using exceptions should be actually saved  
> for situations, the developer cannot predict, such as external io-
> failures etc.

Still in Squeak you have error in collections and read the email of  
Boris this is interesting to ask ourselves the question.

> I am all for letting the programmers know which precondition they  
> violated calling a method, but only for debugging their code, and  
> not for using that info _in_ their code.

I do not like exception either (but catching too high exception  
forces you to typecheck them anyway to do something).

>
> I am aware that there is a slight performance penalty to ask if  
> everything is ok first all the times, also when everything _is_ ok.
> But I'd teach above idiom more as the exception than as the  
> rule... ;-) -- if at all.
>
> Cheers,
>
> Markus
>
>


Reply | Threaded
Open this post in threaded view
|

Re: About use of specific error

Markus Gälli-3
In reply to this post by stéphane ducasse-2
Hi Stef,

>> let's have a look a the following example:
>>
>> Intervall >> remove: anElement
>> self error: 'elements cannot be removed from an Interval'
>>
>> What do you mean with "trapped more specifically"?
>
> Not for this one
> but
> IndexNotFoundError
> KeyNotFoundError
> SubscriptOutOfBoundsError
>
>> I would claim that almost all (happy for any counter example) uses  
>> of "self error:" are indicating that some (maybe implicit)  
>> precondition fails.
>> Being radical I would say in above situation the precondition just  
>> fails always, meaning that this method would never make sense to  
>> be called on Intervals.
>
> But I'm not talking about that in particular.
>
> Dictionary>>at: key
> "Answer the value associated with the key."
>
> ^ self at: key ifAbsent: [self errorKeyNotFound]
>
> errorKeyNotFound
>
> self error: 'key not found'
>
> errorValueNotFound
>
> self error: 'value not found'
>

as I answered Boris:
I am still not convinced that the idiom of "first (possibly) hitting  
the wall, and then asking for the door" is a good one to teach  
students programming.
I think it would be better to teach students a _defensive_ way of  
programming, that is to ask first, if everything is ok, using some  
boolean queries and if these queries do not exist, let them write  
these queries and _not_ exception hierarchies.

So in your examples I would teach to use
        Dictionary >> includesKey:
        Dictionary >> includes:
_before_ calling
        Dictionary >> atKey:
        Dictionary >> keyAtValue:
respectively.

Alternatively
        Dictionary >> at: key ifAbsent: exceptionBlock
        keyAtValue: value ifAbsent: exceptionBlock
are certainly often our best friends here - without having the need  
for any "real" exceptions (and also too much asking before...) ;-)

Cheers,

Markus

Reply | Threaded
Open this post in threaded view
|

Re: About use of specific error

Markus Gälli-3
In reply to this post by stéphane ducasse-2

>>
>> Could you give an example please?
>>
>> I am still not convinced that the idiom of "first (possibly)  
>> hitting the wall, and then asking for the door" is a good one to  
>> teach students programming.
>
> I was not talking about teaching anything.

Ok, I had some nice discussions about that subject in basically all  
my Java classes I had to give... guess I was mixing that up a bit. ;-)
Students love to throw and catch exceptions.

For whom it might concern, there is

> I just asked them to write tests and I was surprised that I have to  
> catch always Error and not more precise Exception.
>
>
>> I think it would be better to teach students a _defensive_ way of  
>> programming, that is to ask first, if everything is ok, using some  
>> boolean queries and if these queries do not exist, let them write  
>> these queries and _not_ exception hierarchies.
>>
>> Exceptions are a way of goto programming and can become quite  
>> hairy to use. I am glad to be in sync here with Andrew Thomas and  
>> Dave Hunt in their nice book about the pragmatic programmer.
>> They write something like using exceptions should be actually  
>> saved for situations, the developer cannot predict, such as  
>> external io-failures etc.
>
> Still in Squeak you have error in collections and read the email of  
> Boris this is interesting to ask ourselves the question.
>
>> I am all for letting the programmers know which precondition they  
>> violated calling a method, but only for debugging their code, and  
>> not for using that info _in_ their code.
>
> I do not like exception either (but catching too high exception  
> forces you to typecheck them anyway to do something).
Don't know. As Error is a subclass of Exception there shouldn't be  
much trouble.

The only three types of exception handling code, that come to my mind  
now, and which I understand, are:

- External IO access, which might fail during the call
- Unit-Tests to check if preconditions are _failing_ correctly
- The _one_ most outer exception-handling code in a deployed  
application, which translates an ugly walkback/red screen/whatever  
into a nice message to the user to calm down, everything will be  
fixed, and to call that number of the helpdesk...

Any I forgot?

Btw., Java folks (in this case Bruce-"Thinking in C++/Java"-Eckel)  
came up with funny ways _not_ to be forced to have exception handling  
code:
http://www.mindview.net/Etc/Discussions/CheckedExceptions

Cheers,

Markus


>>
>> I am aware that there is a slight performance penalty to ask if  
>> everything is ok first all the times, also when everything _is_ ok.
>> But I'd teach above idiom more as the exception than as the  
>> rule... ;-) -- if at all.
>>
>> Cheers,
>>
>> Markus
>>
>>
>
>


Reply | Threaded
Open this post in threaded view
|

Re: Re: About use of specific error

Pascal Meunier-2
In reply to this post by stéphane ducasse-2
It would be easier to catch and therefore to test with a specific subclass of Exception.
Besides, for the Interval>>remove: example, the code would have been:
 
Interval>> remove: anElement
 "elements cannot be removed from an Interval"
 ^self shouldNotImplement
 
Mind you, even in VW you have these calls of error:, and shouldNotImplement is implemented that way...
But why not implementing shouldNotImplement like:
 
Object>> shouldNotImplement
  ^ShouldNotImplementError raise
 
 

Markus Gaelli wrote:
Hi Stef,

let's have a look a the following example:

Intervall >> remove: anElement
self error: 'elements cannot be removed from an Interval'

What do you mean with "trapped more specifically"?

I would claim that almost all (happy for any counter example) uses of
"self error:" are indicating that some (maybe implicit) precondition
fails.
Being radical I would say in above situation the precondition just
fails always, meaning that this method would never make sense to be
called on Intervals.

Using traits we shouldn't need the strange idiom to overwrite
template or other superclass methods, that do not work in special
subclasses, any more.
(It would be really tedious to enumerate all methods on all classes
which do not work... ;-)

If the error string is telling me why the precondition fails, good.
Why would I want to bother with different kinds of exceptions here?

By the way, I call a test, which tests the failing of a precondition,
"pessimistic method example", but I am still open for a better name.
People did not like the name "counter example" or "negative example",
though I still would prefer one of these names and I am about to
rename...

Cheers,

Markus

On Mar 1, 2006, at 10:29 PM, stéphane ducasse wrote:

> Hi all
>
> I asked students of my lecture to write SUnit tests for some
> collections and I noticed that in Squeak
> the collection library do not use specific exception but instead
> use error:.
> The consequence is that it can be tedious to capture only specific
> error. I was wondering what is the
> general feeling about this state. In VW they have various exception
> that can be trapped more specifically.
>
> Stef
>


To help you stay safe and secure online, we've developed the all new Yahoo! Security Centre.

Reply | Threaded
Open this post in threaded view
|

Re: About use of specific error

Markus Gälli-3
Hi Pascal,

> It would be easier to catch and therefore to test with a specific  
> subclass of Exception.

What is wrong with writing:

IntervalTest >> testRemove
        self should: [(1 to: 3) remove: 2] raise: Exception

> Besides, for the Interval>>remove: example, the code would have been:
>
> Interval>> remove: anElement
>  "elements cannot be removed from an Interval"
>  ^self shouldNotImplement

So I need to browse the method and cannot see directly anymore what  
is going in the label of my walkback-window?

>
> Mind you, even in VW you have these calls of error:, and  
> shouldNotImplement is implemented that way...
> But why not implementing shouldNotImplement like:
>
> Object>> shouldNotImplement
>   ^ShouldNotImplementError raise

Why?

Cheers,

Markus

>
>
>
> Markus Gaelli wrote:
> Hi Stef,
>
> let's have a look a the following example:
>
> Intervall >> remove: anElement
> self error: 'elements cannot be removed from an Interval'
>
> What do you mean with "trapped more specifically"?
>
> I would claim that almost all (happy for any counter example) uses of
> "self error:" are indicating that some (maybe implicit) precondition
> fails.
> Being radical I would say in above situation the precondition just
> fails always, meaning that this method would never make sense to be
> called on Intervals.
>
> Using traits we shouldn't need the strange idiom to overwrite
> template or other superclass methods, that do not work in special
> subclasses, any more.
> (It would be really tedious to enumerate all methods on all classes
> which do not work... ;-)
>
> If the error string is telling me why the precondition fails, good.
> Why would I want to bother with different kinds of exceptions here?
>
> By the way, I call a test, which tests the failing of a precondition,
> "pessimistic method example", but I am still open for a better name.
> People did not like the name "counter example" or "negative example",
> though I still would prefer one of these names and I am about to
> rename...
>
> Cheers,
>
> Markus
>
> On Mar 1, 2006, at 10:29 PM, stéphane ducasse wrote:
>
> > Hi all
> >
> > I asked students of my lecture to write SUnit tests for some
> > collections and I noticed that in Squeak
> > the collection library do not use specific exception but instead
> > use error:.
> > The consequence is that it can be tedious to capture only specific
> > error. I was wondering what is the
> > general feeling about this state. In VW they have various exception
> > that can be trapped more specifically.
> >
> > Stef
> >
>
>
> To help you stay safe and secure online, we've developed the all  
> new Yahoo! Security Centre.
>


Reply | Threaded
Open this post in threaded view
|

Re: About use of specific error

Julian Fitzell


Markus Gaelli wrote:

> Hi Pascal,
>
>> It would be easier to catch and therefore to test with a specific  
>> subclass of Exception.
>
>
> What is wrong with writing:
>
> IntervalTest >> testRemove
>     self should: [(1 to: 3) remove: 2] raise: Exception

Presumably because the class you are testing may be calling another
class to do some work and *it* might be raising an exception.  It's a
little hard to imagine a good example for this particular case but
perhaps it's looking up a preference and Squeak can't find the
Preferences file.  But if that preferences file *was* there, then that
could would happily carry on without raising an exception.  Your test
*should* be failing, it's just getting disguised.

But I do agree there is some difference between, say, a network
exception that might prompt you to retry your behaviour vs. an exception
saying "you're using the code wrong, buddy!".  In the latter case, there
does seem to be less advantage to having specific subclasses.

We should keep in mind that subclassing exceptions is not just to
provide the ability to differentiate between them when they are caught
though.  One of the great powers of exceptions here is having the
ability to specify default behaviour.  This allows the programmer to
catch all exceptions during debugging but may in fact allow the program
(or the user) to decide to continue on with a valid default when the
program is really running.

Sorry for the stream of consciousness email... :)

Julian

Reply | Threaded
Open this post in threaded view
|

Re: About use of specific error

Lukas Renggli
In reply to this post by Markus Gälli-3
> What is wrong with writing:
>
> IntervalTest >> testRemove
>         self should: [(1 to: 3) remove: 2] raise: Exception

If you accidently write (note the typing error in the selector)

IntervalTest >> testRemove
      self should: [(1 to: 3) remve: 2] raise: Exception

you get a test that always succeeds.

Lukas

--
Lukas Renggli
http://www.lukas-renggli.ch

Reply | Threaded
Open this post in threaded view
|

Re: About use of specific error

Markus Gälli-3
Pascal, Lukas and Julian,

>> What is wrong with writing:
>>
>> IntervalTest >> testRemove
>>         self should: [(1 to: 3) remove: 2] raise: Exception
>
> If you accidently write (note the typing error in the selector)
>
> IntervalTest >> testRemove
>       self should: [(1 to: 3) remve: 2] raise: Exception
>
> you get a test that always succeeds.
>

and

> Presumably because the class you are testing may be calling another  
> class to do some work and *it* might be raising an exception.  It's  
> a little hard to imagine a good example for this particular case  
> but perhaps it's looking up a preference and Squeak can't find the  
> Preferences file.  But if that preferences file *was* there, then  
> that could would happily carry on without raising an exception.  
> Your test *should* be failing, it's just getting disguised.
>
> But I do agree there is some difference between, say, a network  
> exception that might prompt you to retry your behaviour vs. an  
> exception saying "you're using the code wrong, buddy!".  In the  
> latter case, there does seem to be less advantage to having  
> specific subclasses.
>
> We should keep in mind that subclassing exceptions is not just to  
> provide the ability to differentiate between them when they are  
> caught though.  One of the great powers of exceptions here is  
> having the ability to specify default behaviour.  This allows the  
> programmer to catch all exceptions during debugging but may in fact  
> allow the program (or the user) to decide to continue on with a  
> valid default when the program is really running.
>
> Sorry for the stream of consciousness email... :)

Thanks for clarifying. These counter examples make much sense.
So I'd suggest to come up with sth like:

  PreconditionError >> error: aString

so that above became:

IntervalTest >> testRemove
         self should: [(1 to: 3) remove: 2] raise: PreconditionError

What do you think? Could you agree to see this call as violating a  
precondition?
Think of the receiver as the 0th parameter, in that case certainly  
always wrong...aeh...is it?

Actually creating an empty interval  seems to be allowed. So why  
can't I remove an element of an interval with only one value?
Speaking more general, removing the last or first element of an  
interval would keep the class invariant intact - if the interval has  
at least one element of course.

Cheers,

Markus

Reply | Threaded
Open this post in threaded view
|

Re: About use of specific error

Andreas.Raab
In reply to this post by stéphane ducasse-2
stéphane ducasse wrote:

>> Intervall >> remove: anElement
>>     self error: 'elements cannot be removed from an Interval'
>>
>> What do you mean with "trapped more specifically"?
>
> Not for this one
>     but
>         IndexNotFoundError
>         KeyNotFoundError
>         SubscriptOutOfBoundsError

I have often wondered about the usefulness of such hierarchies. The way
I look at it, an exception hierarchy is useful if and only if one has a
need to handle the exceptions individually. And what's interesting here
is that in particular the above seem to be cases where nobody ever
handles them (and doesn't have the need to since there are always
variants that explicitly avoid the error condition like #at:ifAbsent:
#removeKey:ifAbsent: etc). Therefore I'd claim that if you have a case
where a client handles an exception by looking at the error text, then
by all means, make it a separate entity. But otherwise, don't make the
system more complex than it needs to be.

Cheers,
   - Andreas

Reply | Threaded
Open this post in threaded view
|

Re: About use of specific error

stéphane ducasse-2
In reply to this post by Markus Gälli-3
Markus
can you read what I wrote.... I'm not teaching anything here related  
to first checking if a key exist or not, or
how to use a dictionary......

I'm teaching them to write tests and to write tests for a class that  
raises exceptions
you have to catch them and to cover the potential behavior of the  
class! This is not my wish or not to have exceptions, they are there  
and to cover the method behavior (because of different programming  
style) I have to cover them.

For example, what happens if we access an element at not existing index.

Stef


On 2 mars 06, at 14:14, Markus Gaelli wrote:

> Hi Stef,
>
>>> let's have a look a the following example:
>>>
>>> Intervall >> remove: anElement
>>> self error: 'elements cannot be removed from an Interval'
>>>
>>> What do you mean with "trapped more specifically"?
>>
>> Not for this one
>> but
>> IndexNotFoundError
>> KeyNotFoundError
>> SubscriptOutOfBoundsError
>>
>>> I would claim that almost all (happy for any counter example)  
>>> uses of "self error:" are indicating that some (maybe implicit)  
>>> precondition fails.
>>> Being radical I would say in above situation the precondition  
>>> just fails always, meaning that this method would never make  
>>> sense to be called on Intervals.
>>
>> But I'm not talking about that in particular.
>>
>> Dictionary>>at: key
>> "Answer the value associated with the key."
>>
>> ^ self at: key ifAbsent: [self errorKeyNotFound]
>>
>> errorKeyNotFound
>>
>> self error: 'key not found'
>>
>> errorValueNotFound
>>
>> self error: 'value not found'
>>
>
> as I answered Boris:
> I am still not convinced that the idiom of "first (possibly)  
> hitting the wall, and then asking for the door" is a good one to  
> teach students programming.
> I think it would be better to teach students a _defensive_ way of  
> programming, that is to ask first, if everything is ok, using some  
> boolean queries and if these queries do not exist, let them write  
> these queries and _not_ exception hierarchies.
>
> So in your examples I would teach to use
> Dictionary >> includesKey:
> Dictionary >> includes:
> _before_ calling
> Dictionary >> atKey:
> Dictionary >> keyAtValue:
> respectively.
>
> Alternatively
> Dictionary >> at: key ifAbsent: exceptionBlock
> keyAtValue: value ifAbsent: exceptionBlock
> are certainly often our best friends here - without having the need  
> for any "real" exceptions (and also too much asking before...) ;-)

Again this is not the point, even if I agree on the use of ifAbsent:....
These are idioms and I'm talking here about test coverage!

Stef


Reply | Threaded
Open this post in threaded view
|

RE: About use of specific error

Bany, Michel
In reply to this post by stéphane ducasse-2
 

> I'm teaching them to write tests and to write tests for a
> class that raises exceptions you have to catch them and to
> cover the potential behavior of the class! This is not my
> wish or not to have exceptions, they are there and to cover
> the method behavior (because of different programming
> style) I have to cover them.
>
> For example, what happens if we access an element at not
> existing index.

Why not have your students write tests like this

IntervalTest >> testRemove

      self should: [(1 to: 3) remove: 2] raise: Exception.

      [(1 to: 3) remove: 2]
                on: Exception do:

                [:ex |
                self assert: ex class == Error.
                self assert: ex description = 'elements cannot be
removed from an Interval'].

This clearly describes what is expected from the Interval class.

Michel.

Reply | Threaded
Open this post in threaded view
|

Re: About use of specific error

stéphane ducasse-2
In reply to this post by Andreas.Raab

On 2 mars 06, at 18:55, Andreas Raab wrote:

> stéphane ducasse wrote:
>>> Intervall >> remove: anElement
>>>     self error: 'elements cannot be removed from an Interval'
>>>
>>> What do you mean with "trapped more specifically"?
>> Not for this one
>>     but
>>         IndexNotFoundError
>>         KeyNotFoundError
>>         SubscriptOutOfBoundsError
>
> I have often wondered about the usefulness of such hierarchies. The  
> way I look at it, an exception hierarchy is useful if and only if  
> one has a need to handle the exceptions individually.


Exact! I do not know if people ever tried to catch these ones. I have  
the impression that this is really an idiom in Smalltalk. In Java you  
get really a lot of exceptions everywhere. The comparison is  
interesting.
I do not have the taste right now to have strong arguments pros or  
cons. This is why I asked to see the reaction and
improve my exception taste.

> And what's interesting here is that in particular the above seem to  
> be cases where nobody ever handles them (and doesn't have the need  
> to since there are always variants that explicitly avoid the error  
> condition like #at:ifAbsent: #removeKey:ifAbsent: etc). Therefore  
> I'd claim that if you have a case where a client handles an  
> exception by looking at the error text, then by all means, make it  
> a separate entity. But otherwise, don't make the system more  
> complex than it needs to be.

Yes. Now the difficulty is to know when you are designing your system  
in advance how your clients will use it.
May be KISS and wait and see.

One exception that I like to trap was the "filein error" that you  
would get when you define a class by sending a message
to a superclass that does not exist :). In VW it lets me load broken  
or partial code that I just need to browse and analyze but not run

Stef



Reply | Threaded
Open this post in threaded view
|

Re: About use of specific error

Markus Gälli-3
In reply to this post by stéphane ducasse-2
Stef,

> can you read what I wrote.... I'm not teaching anything here  
> related to first checking if a key exist or not, or
> how to use a dictionary......
>
> I'm teaching them to write tests and to write tests for a class  
> that raises exceptions
> you have to catch them and to cover the potential behavior of the  
> class! This is not my wish or not to have exceptions, they are  
> there and to cover the method behavior (because of different  
> programming style) I have to cover them.
Agreed already yesterday. As I said/ wanted to say: Maybe I pushed  
the discussing about exception-handling teaching a bit too hard due  
to intensive discussions I had with students during _my_ java classes  
but:
>
> For example, what happens if we access an element at not existing  
> index.
I think overall the discussion here was quite fruitful!

To summarize:

1.) I learned that it makes sense to subclass Error or Exception for  
testing reasons.
Otherwise one does not know if an exception was thrown by the method  
under test due to a misspelled method name (point of Lukas)
or some other method had a problem on the way (point of  Julian).

2.) My point is to use one(!) subclass of Error called  
PreconditionError for all unit tests I call "counter examples":

>  PreconditionError >> error: aString
>
> so that above became:
>
> IntervalTest >> testRemove
>         self should: [(1 to: 3) remove: 2] raise: PreconditionError

I claim that all counter examples check the correct handling of  
violating a precondition. Using that abstraction also solves the  
problems above.
I invite you all to point out some counter examples for that. ;-)

3.) A very interesting question to ask is if violating a precondition  
propagates back -
meaning that if I call a method foo which calls a method bar, which  
throws a PreconditionError can be correctly caught with "counter  
example" for method foo - even if foo does not(!) contain THAT  
precondition.
I think this to be a feature, as otherwise I would have to write the  
same preconditions all over again.

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.

So a "counter example" for solveQuadraticEquation could(!) look like:

ArrayTest >> #testSolveQuadraticEquation
        "The following PreconditionError is _not_ thrown by  
#solveQuadraticEquation but by sqrt!!!"
        self should: [#(1 12 37) solveQuadraticEquation] raise:  
PreconditionError
       
Right now of course sqrt throws a FloatingPointException which is  
referenced nowhere (!) in the whole system and which does not contain  
any method at all.
This would usually qualify as quite a bogus class.

4.) Actually by using the perspective of PreconditionError I could  
spot a possible mistake in the implementation of Interval:
One should be allowed to remove (and add) the first and last element
(s) in an Interval, at least mathematically nothing would speak
against it as long as the invariant of representing a "finite  
arithmetic progression" (class comment of Interval) would be intact.

So possibly a better "method test suite" for Interval >>#remove:  
would contain a "counter example" and a "method test": (names in  
quotes taken from my unit test classification)

IntervalTest >> testRemove
        |anInterval|

         self should: [(1 to: 3) remove: 2] raise: PreconditionError
        anInterval := 1 to: 3.
        anInterval remove: 3.
        self assert: (anInterval = (1 to: 2))

5.) Andreas, Boris and Pascal point was to use subclasses of  
Exception when you are forced to otherwise programmatically deal with  
an error string.
I agree with this! Andreas and me were cautious about introducing to  
many exception subclasses.
>>>
>>> Not for this one
>>> but
>>> IndexNotFoundError
>>> KeyNotFoundError
>>> SubscriptOutOfBoundsError
We still haven't seen a compelling reason to introduce above  
exception-classes. I thought you were proposing them but could not  
find any argument for them.
Reading your reply to Andreas it seems that you just wanted to  
provoke... ;-)

As I said, I think you provoked a fruitful discussion.

Cheers,

Markus

Reply | Threaded
Open this post in threaded view
|

Re: About use of specific error

Markus Gälli-3

On Mar 3, 2006, at 12:22 PM, Markus Gaelli wrote:

> IntervalTest >> testRemove
> |anInterval|
>
>         self should: [(1 to: 3) remove: 2] raise: PreconditionError
> anInterval := 1 to: 3.
> anInterval remove: 3.
> self assert: (anInterval = (1 to: 2))
>
>

Actually mathematically speaking it is certainly correct to remove 2  
from (1 to: 3)  as (1 to: 3 by: 2) is an Interval too... ;-)

So I correct above "method test suite" into:

IntervalTest >> testRemove
        |anInterval|

         self should: [(1 to: 4) remove: 2] raise: PreconditionError.
        anInterval := 1 to: 3.
        anInterval remove: 2.
        self assert: (anInterval = (1 to: 3 by: 2)).
        anInterval := 1 to: 3.
        anInterval
                remove: 3;
                remove: 1;
                remove: 2.
        self assert: anInterval isEmpty

Cheers,

Markus



123