Users of UnhandledError definitely shows that it is a critical bug.

For example we rely on UnhandledError in Announcer to ensure that all
subscriptions will be processed independently on errors signalled by any of
them:

ann := Announcer new.
ann when: ValueChanged do: [:ann | 1 logCr. 1/0 ].
ann when: ValueChanged do: [:ann | 2 logCr. 2/0 ].
ann when: ValueChanged do: [:ann | 3 logCr. 3/0 ].


ann announce: ValueChanged new


It will show 1, 2, 3 in transcript and open 3 debuggers. Each error is
deferred to the background process allowing the delivery to continue:

AnnouncementSubscription>>deliver: anAnnouncement

" deliver an announcement to receiver. In case of failure, it will be
handled in separate process"


^ (self handlesAnnouncement: anAnnouncement ) ifTrue: [

[action cull: anAnnouncement cull: announcer]

on: UnhandledError fork: [:ex | ex pass ]]


Now if you will try to wrap #announce: into handler block the deliver will
be interrupted by first error:

[ann announce: ValueChanged new] on: ZeroDivide do: [ :err | err logCr. err
pass ].


It will open single debugger at first handler error.

ср, 18 дек. 2019 г. в 20:44, Denis Kudriashov <[email protected]>:

> Hi.
>
> I played a bit with exceptions trying to detect that given block will open
> the debugger. My idea was to simply catch UnhandledError which normally
> means that no outer code handles given error and therefore debugger is
> appeared.
> For my surprise the following example works from playground but not from
> the browser editor:
>
>
> [MyTestError signal ] on: UnhandledError do: [ :e | self halt ]
>
>
> In playground you will see the halt. But from the browser the debugger
> will show MyTestError.
>
> After breaking my head I found that there is a difference how scripts are
> executed in those tools. In Playground it is a deferred action. But in the
> browser it is evaluated as a deep event processing code (keymap processing)
> and there is an outer error handler (on: Error do: ) which does some work
> and passes the exception further (err pass).
> Following script demonstrates the difference in the error processing logic
> when there is an outer handler:
>
>
> [
>
> [MyTestError signal ] on: UnhandledError do: [ :e | self halt ]
>
>  ] on: MyTestError do: [ :z | z pass]
>
>
> Try it from playground. Second line separately will show the halt while
> all together it will stop at MyTestError signal.
>
> Debugging shows that when the outer handler is processed it sets the
> handler context into the exception and it skips the existing handler for
> UnhandledError.
>
> The question: is it a feature or a bug?
> Think also how following code should work (unrelated to UnhandledError
> logic):
>
> [
>
> [ 1/0 ] on: MyTestError do: [ :e | self halt ]
>
>  ] on: ZeroDivide do: [ :z | MyTestError signal ]
>
>
> Currently it will show MyTestError signal.
>
> Best regards,
> Denis
>

Reply via email to