Exception Handling

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

Exception Handling

Zulq Alam
Hello,

I'm a bit confused about exception handling, perhaps you can help please?

If I have a method #foo and #foo can signal two errors FooError and
UnrelatedToFooError how do I handle both errors using #on:do: without
having something like...

[someObject foo]
    on: Error
    do: [:error | (error class = FooError) ifTrue: ["do something
specific to FooError"].
          (error class = UnrelatedToFooError) ifTrue: ["do something
specific to UnrelatedToFooError"]].

In Java I would do something like

try {
    somObject.foo();
}
catch (FooError e) {
    // do something specific to FooError
}
catch (UnrelatedToFooError e) {
    // do something specific to UnrelatedToFooError
}

Even if under the hood the same is happening this seems to take care of
some very common code.

Is there something in Smalltalk/Squeak will provide something similar?

Thanks,
Zulq.


Reply | Threaded
Open this post in threaded view
|

Re: Exception Handling

Chris Muller-2
If you wish to handle FooError and UnrelatedToFooError in the same way, you can use the concatenation operator:
 
     [ someObject foo ]
         on: FooError, UnrelatedToFooError
         do: [ : err | "handle the err" ]
 
 If, however, you wish to handle them differently you may nest them:
 
     [ [ someObject foo ]
         on: FooError
         do: [ :fooErr | "handle fooErr" ] ]
             on: UnrelatedToFooError
             do: [ :unToFooErr | "..." ]
 
 For this second case, I implemented a helper method on BlockContext that allows me to specify multiple handlers conveniently without nesting:
 
 BlockContext>>#maOn: exc1 do: block1 on: exc2 do: block2
     ^ [
             [ self value ]
                 on: exc1
                 do: block1 ]
 
         on: exc2
         do: block2
 
 Hope this helps..
 
  - Chris

 
----- Original Message ----
From: Zulq Alam <[hidden email]>
To: The general-purpose Squeak developers list <[hidden email]>
Sent: Monday, March 20, 2006 2:12:48 PM
Subject: Exception Handling

Hello,

I'm a bit confused about exception handling, perhaps you can help please?

If I have a method #foo and #foo can signal two errors FooError and
UnrelatedToFooError how do I handle both errors using #on:do: without
having something like...

[someObject foo]
    on: Error
    do: [:error | (error class = FooError) ifTrue: ["do something
specific to FooError"].
          (error class = UnrelatedToFooError) ifTrue: ["do something
specific to UnrelatedToFooError"]].

In Java I would do something like

try {
    somObject.foo();
}
catch (FooError e) {
    // do something specific to FooError
}
catch (UnrelatedToFooError e) {
    // do something specific to UnrelatedToFooError
}

Even if under the hood the same is happening this seems to take care of
some very common code.

Is there something in Smalltalk/Squeak will provide something similar?

Thanks,
Zulq.







Reply | Threaded
Open this post in threaded view
|

Re: Exception Handling

Nicolas Cellier-3
In reply to this post by Zulq Alam
Le Lundi 20 Mars 2006 21:12, Zulq Alam a écrit :

> Hello,
>
> I'm a bit confused about exception handling, perhaps you can help please?
>
> If I have a method #foo and #foo can signal two errors FooError and
> UnrelatedToFooError how do I handle both errors using #on:do: without
> having something like...
>
> [someObject foo]
>     on: Error
>     do: [:error | (error class = FooError) ifTrue: ["do something
> specific to FooError"].
>           (error class = UnrelatedToFooError) ifTrue: ["do something
> specific to UnrelatedToFooError"]].
>

If handler blocks are different, you might nest the two

[[someObject foo]
        on: FooError
        do: [:error | "do something specific to FooError"]]
    on: UnrelatedToFooError
    do: [:error | "do something specific to UnrelatedToFooError"].

It's a little like the if/elseif chain, you have to nest them in Smalltalk.
Otherwise, you could try and implement your own multiple error messages
 on:do:on:do:
 on:do:on:do:on:do:

If handler blocks are the same, there is the possibility to handle a
collection of errors in Visualworks,
  [someObject foo]
        on: FooError , UnrelatedToFooError
        do: [:error | "do something common to FooError and
UnrelatedToFooError"].

but i did not see anything like this in Squeak... unless i missed something.
Has anyone got elegant a solution for the second case ?

Nicolas


Reply | Threaded
Open this post in threaded view
|

Re: Exception Handling

Nicolas Cellier-3
In reply to this post by Zulq Alam

> If handler blocks are the same, there is the possibility to handle a
> collection of errors in Visualworks,
>   [someObject foo]
>         on: FooError , UnrelatedToFooError
>         do: [:error | "do something common to FooError and
> UnrelatedToFooError"].
>
> but i did not see anything like this in Squeak... unless i missed
> something. Has anyone got elegant a solution for the second case ?
>
> Nicolas

OK, Chris was faster, and also answered my question:

(FooError , UnrelatedToFooError) is implemented of course in
Exception class>>#,

Nicolas


Reply | Threaded
Open this post in threaded view
|

RE: Exception Handling

Ron Teitelbaum
In reply to this post by Nicolas Cellier-3
> From: nicolas cellier
> Sent: Monday, March 20, 2006 3:42 PM
>
> Le Lundi 20 Mars 2006 21:12, Zulq Alam a écrit :
> > Hello,
> >
> > I'm a bit confused about exception handling, perhaps you can help
> please?
> >
> > If I have a method #foo and #foo can signal two errors FooError and
> > UnrelatedToFooError how do I handle both errors using #on:do: without
> > having something like...
> >
> > [someObject foo]
> >     on: Error
> >     do: [:error | (error class = FooError) ifTrue: ["do something
> > specific to FooError"].
> >           (error class = UnrelatedToFooError) ifTrue: ["do something
> > specific to UnrelatedToFooError"]].
> >
>
> If handler blocks are different, you might nest the two
>
> [[someObject foo]
>         on: FooError
>         do: [:error | "do something specific to FooError"]]
>     on: UnrelatedToFooError
>     do: [:error | "do something specific to UnrelatedToFooError"].
>
> It's a little like the if/elseif chain, you have to nest them in
> Smalltalk.
> Otherwise, you could try and implement your own multiple error messages
>  on:do:on:do:
>  on:do:on:do:on:do:
>
> If handler blocks are the same, there is the possibility to handle a
> collection of errors in Visualworks,
>   [someObject foo]
>         on: FooError , UnrelatedToFooError
>         do: [:error | "do something common to FooError and
> UnrelatedToFooError"].
>
> but i did not see anything like this in Squeak... unless i missed
> something.
> Has anyone got elegant a solution for the second case ?
>
> Nicolas
>
>

Also you might keep in mind that subclasses of errors are handled also.

If FooError were a subclass of UnrelatedToFooError, then the handler for
UnrelatedToFooError would catch both.  

It's also a nice trick to put the handler on the error.  
In that case you get the following

[someObject foo]
        on: UnrelatedToFooError   "handles subclasses"
        do: [:error | error handleError].

Then

UnrelatedToFooError >> handleError
        "Do something unrelated to Foo"

FooError >> handleError
        "Do something related to Foo"

You could also use a error handleErrorWith: aSomethingOrOther

And then you could send it some context for handling your error.  Say if the
Error wrapper is on an application then handleErrorWith: anApplication would
give your errorHandler the application that it could use for handling the
error.

Happy coding!

Ron Teitelbaum



Reply | Threaded
Open this post in threaded view
|

Re: Exception Handling

Boris.Gaertner
In reply to this post by Zulq Alam
"Zulq Alam" <[hidden email]> wrote:

> Hello,
>
> I'm a bit confused about exception handling, perhaps you can help please?
>
> If I have a method #foo and #foo can signal two errors FooError and
> UnrelatedToFooError how do I handle both errors using #on:do: without
> having something like...
>
> [someObject foo]
>     on: Error
>     do: [:error | (error class = FooError) ifTrue: ["do something
> specific to FooError"].
>           (error class = UnrelatedToFooError) ifTrue: ["do something
> specific to UnrelatedToFooError"]].
>
> In Java I would do something like
>
> try {
>     somObject.foo();
> }
> catch (FooError e) {
>     // do something specific to FooError
> }
> catch (UnrelatedToFooError e) {
>     // do something specific to UnrelatedToFooError
> }
>
> Even if under the hood the same is happening this seems to take care of
> some very common code.
>
> Is there something in Smalltalk/Squeak will provide something similar?
>
Not exactly. The
      try {...} catch{...} catch {...} ...
is similar to the well-known case-statement in that it enumerates
a variable number of cases. This does not fit into the message
syntax that does not allow for a variable number of message
arguments.

Given this restriction it is the correct solution to let the
handler check the class of the exception.

There is however one peculiarity that I should mention:

The on: Error do: <handler>

catches all exception that are represented as instances of Error
or as instances of subclasses of Error.When you use this construct
to handle only exceptions of types  FooError  and UnrelatedToFooError,
you may have to propagate (resignal) all exceptions that you do not want
to handle.

You can however set up a handler that does not catch all Errors,
but only the exceptions you are intersted in:

 /* example 1 */
 [someObject foo]
   on: FooError, UnrelatedToFooError
   do: [ error |
         (error class = FooError)
            ifTrue: ["do something specific to FooError"].
        (error class = UnrelatedToFooError)
          ifTrue: ["do something specific to UnrelatedToFooError"]
       ].

The message  #, is defined in the class protocol of classes
Exception and ExceptionSet. It is used to group
exceptions into exception sets.


I think you can even write:

/* example 2*/
 [someObject foo]
   on: FooError, UnrelatedToFooError
   do: [ error |
          error class caseOf:
             { [FooError] ->  ["do something specific to FooError"].
                [UnrelatedToFooError] -> ["do something specific to
UnrelatedToFooError"]
             }.
       ].

Please have a look at Object >> caseOf:  if you think this
may be useful for you.

Note that there is a difference between example 1 and this
statement:

 [someObject foo]
   on: FooError, UnrelatedToFooError
   do: [ error |
         (error class isKindOf: FooError)
            ifTrue: ["do something specific to FooError"].
        (error class isKindOf: UnrelatedToFooError)
          ifTrue: ["do something specific to UnrelatedToFooError"]
       ].

With this statement you can handle also exceptions that
are represented by subclasses of either FooError or
UnrelatedToFooErrror.

Example 1 and example 2 are equivalent it that they both handle
only exceptions of classes  FooError, UnrelatedToFooError.


This is not exactly what you hope to read, but
it may illustrate some less frequently explained aspects
of exceptions handling.

Greetings,
Boris


Reply | Threaded
Open this post in threaded view
|

Re: Exception Handling

Zulq Alam
In reply to this post by Chris Muller-2
Thank you all. All makes sense now.

Z.

Chris Muller wrote:

> If you wish to handle FooError and UnrelatedToFooError in the same way, you can use the concatenation operator:
>  
>      [ someObject foo ]
>          on: FooError, UnrelatedToFooError
>          do: [ : err | "handle the err" ]
>  
>  If, however, you wish to handle them differently you may nest them:
>  
>      [ [ someObject foo ]
>          on: FooError
>          do: [ :fooErr | "handle fooErr" ] ]
>              on: UnrelatedToFooError
>              do: [ :unToFooErr | "..." ]
>  
>