"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 |
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 > > > |
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 |
Free forum by Nabble | Edit this page |