Exception handling

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

Exception handling

cdavidshaffer
"Here are some musings on exception handling and a method I'm playing
with.  I'd appreciate the eyes of someone more versed in this.

ensure block runs after handler block has returned (but this is not a
resumable error)"
[
    [1/0] ensure: [Transcript show: 'ensure'; cr]
] on: Error do: [:ex | Transcript show: 'handler'; cr]

"produces:

handler
ensure"


"...makes sense for Notifications since we might 'ex resume: someValue'"
[
    [Notification signal: 'yes'] ensure: [Transcript show: 'ensure'; cr].
] on: Notification do: [:ex | Transcript show: 'handler'; cr]

"what if we retry the block?  works as expected...ensure block runs
before block retried."
retried := false.
[
    [1/0] ensure: [Transcript show: 'ensure'; cr]
] on: Error do: [:ex | Transcript show: 'handler'; cr.
    retried ifFalse: [retried := true. ex retry]]

"produces

handler
ensure
handler
ensure"

"OK...consistency is nice but what if our handler really doesn't plan or
can't resume an exception.
I propose:"

[
    [1/0] ensure: [Transcript show: 'ensure'; cr]
] on: Error unwindAndDo: [:ex | Transcript show: 'handler'; cr.
    retried ifFalse: [retried := true. ex retry]]

"which produces

ensure
handler


The on:unwindAndDo: semantics are important if the handler needs to
access a resource protected by a mutex and used in the protected block.  
So:"

mutex := Semaphore forMutualExclusion.
[
    mutex critical: [Error signal: 'I am bad']
] on: Error unwindAndDo: [mutex critical: [Transcript show: 'handler'; cr]]

"
produces

handler

rather than deadlocking as it would with on:do:

Here is a hackish implementation:

BlockContext>>on: exception unwindAndDo: handler
    ^self on: exception do: [:ex |
          (ex instVarNamed: #signalContext) unwindTo: (ex instVarNamed:
#handlerContext).
        handler value]


I'm driving without a map here...does anyone else find this to be a
useful exception handling pattern?  Has this been hashed over before?  
Is the above code horribly evil (besides the obvious intrusion of
instVarNamed:)?

"

David


Reply | Threaded
Open this post in threaded view
|

Re: Exception handling

Andreas.Raab
What you are describing is pretty much the semantics of ifCurtailed:, e.g.,

[
   [1/0] ensure: [Transcript show: 'ensure'; cr]
] ifCurtailed:[Transcript show: 'handler'; cr]

Cheers,
   - Andreas


C. David Shaffer wrote:

> "Here are some musings on exception handling and a method I'm playing
> with.  I'd appreciate the eyes of someone more versed in this.
>
> ensure block runs after handler block has returned (but this is not a
> resumable error)"
> [
>    [1/0] ensure: [Transcript show: 'ensure'; cr]
> ] on: Error do: [:ex | Transcript show: 'handler'; cr]
>
> "produces:
>
> handler
> ensure"
>
>
> "...makes sense for Notifications since we might 'ex resume: someValue'"
> [
>    [Notification signal: 'yes'] ensure: [Transcript show: 'ensure'; cr].
> ] on: Notification do: [:ex | Transcript show: 'handler'; cr]
>
> "what if we retry the block?  works as expected...ensure block runs
> before block retried."
> retried := false.
> [
>    [1/0] ensure: [Transcript show: 'ensure'; cr]
> ] on: Error do: [:ex | Transcript show: 'handler'; cr.
>    retried ifFalse: [retried := true. ex retry]]
>
> "produces
>
> handler
> ensure
> handler
> ensure"
>
> "OK...consistency is nice but what if our handler really doesn't plan or
> can't resume an exception.
> I propose:"
>
> [
>    [1/0] ensure: [Transcript show: 'ensure'; cr]
> ] on: Error unwindAndDo: [:ex | Transcript show: 'handler'; cr.
>    retried ifFalse: [retried := true. ex retry]]
>
> "which produces
>
> ensure
> handler
>
>
> The on:unwindAndDo: semantics are important if the handler needs to
> access a resource protected by a mutex and used in the protected block.  
> So:"
>
> mutex := Semaphore forMutualExclusion.
> [
>    mutex critical: [Error signal: 'I am bad']
> ] on: Error unwindAndDo: [mutex critical: [Transcript show: 'handler'; cr]]
>
> "
> produces
>
> handler
>
> rather than deadlocking as it would with on:do:
>
> Here is a hackish implementation:
>
> BlockContext>>on: exception unwindAndDo: handler
>    ^self on: exception do: [:ex |
>          (ex instVarNamed: #signalContext) unwindTo: (ex instVarNamed:
> #handlerContext).
>        handler value]
>
>
> I'm driving without a map here...does anyone else find this to be a
> useful exception handling pattern?  Has this been hashed over before?  
> Is the above code horribly evil (besides the obvious intrusion of
> instVarNamed:)?
>
> "
>
> David
>
>
>


Reply | Threaded
Open this post in threaded view
|

Re: Exception handling

cdavidshaffer
Andreas Raab wrote:
> What you are describing is pretty much the semantics of ifCurtailed:,
> e.g.,
>
> [
>   [1/0] ensure: [Transcript show: 'ensure'; cr]
> ] ifCurtailed:[Transcript show: 'handler'; cr]
>
Yes, thanks, but maybe not quite since mine can handle specific
exceptions and, with a slight modification to the code I supplied, it
can provide the exception which caused the block to exit prematurely.  
ifCurtailed: is implemented as a primitive so I'm not sure how to build
off of it to get those features.  The former feature probably isn't so
useful since most of the time this "unwind" semantics is only needed for
catch-all error handlers like ifCurtailed: provides.

David