[Cuis-dev] Exception handler blocks with non-local returns
Phil B
pbpublist at gmail.com
Tue Nov 5 08:17:16 PST 2019
Andres,
On Tue, Nov 5, 2019 at 1:15 AM Andres Valloud via Cuis-dev <
cuis-dev at lists.cuis.st> wrote:
> I'm more familiar with how a message such as #receive would be
> implemented in some socket class, than how applications tend to write
> code that uses that functionality. So, suppose you had a method like this:
>
> doTheHttpThing
>
> | data |
> self prepareToDoTheHttpThing.
> data := [self socket receive] on: SocketError do: [:ex | ^nil].
> data preprocess filter blah blah.
> ^data
>
>
Many times, you're not dealing with a single http request, but a series of
interrelated requests that represent a conversation. This is somewhat
subjective in terms of how one answers the question 'when does it make
sense to break this out into it's own method?' but I often end up with
something like:
doTheHttpThing
So now the problem that the on:do: is dealing with is what happens when
> the socket disconnects from under the client code. Then #receive fails,
> there is no recourse, and the answer should be nil. One could do the
> wrap around like this:
>
> data := [self socket receive] on: SocketError do: [:ex | nil].
> data isNil ifTrue: [^nil].
>
> and I'd be tempted to write it that way now because who knows that ^nil
> does today. But suppose that no, that one would rather not have extra
> statements. Then one might want something like [:ex | ex methodReturn:
> nil] instead.
>
> In this case, why couldn't that be written like this?
>
> | data |
> ^[
> self prepareToDoTheHttpThing.
> data := self socket receive.
> data preprocess filter blah blah.
> data
> ] on: SocketError do: [:ex | nil]
>
> Now there's no non-local return as far as exceptions are concerned, and
> by the way the code is faster in all cases because non-local return is
> expensive.
>
> Once I wrote a multi-process web spider, and I remember writing the code
> so that the actual networking interaction happened in a very small place
> that could be controlled easily with patterns such as the above. Is the
> problem that application code doesn't always factor that nicely to allow
> that implementation strategy? I do not have enough of a sample to tell.
>
> > For example, I have a periodic task which involves ~10k http requests.
> > A couple hundred of those will fail each run for various reasons:
> > network errors, server down, server errors, page errors etc. There are
> > exception handlers at different levels of connection/request handling
> > that decide if the error is something that needs to be specifically
> > handled / retried or if terminating the request (or perhaps it was
> > terminated on us) and returning some specific value to the sender is the
> > appropriate result. These are almost always non-local returns since
> > we're failing right in the middle of processing a request which is no
> > longer valid.
>
> I suspect this is one of those cases where the code just doesn't factor
> nicely, right?
>
> > 3) FFI code and dealing with the 'outside world' more generally.
> > Similar situation as 2: something fails either in an expected place or
> > in an expected way. The current method can't continue but the sender
> > can. Examples: a non-critical log file or database can't be found or
> > has a problem... (maybe) log something to transcript and return from the
> > method in question. A backup file can't be copied to a secondary backup
> > location... we probably aren't connected to the network so ignore it and
> > try again the next time we get called. I have several of these: fatal
> > to the current method but the sender doesn't care.
> >
> > The thing all of these examples have in common is that they are all
> > essentially resumable, fatal exceptions... that need to resume somewhere
> > else.
>
> Maybe more like critical exceptions that are not fatal simply because of
> the context in which they occur.
>
> You know, it just occurred to me that having such exceptions implement a
> #defaultAction method isn't really useful, either. Suppose you could
> arrange the code so that the non-fatal yet critical exceptions were
> modeled by a particular class. Instead of a million exception handlers
> everywhere doing something like
>
> [...] on: NonFatalIOError do: [:ex | ex methodReturn: nil]
>
> one would like #defaultAction to do that. However, #defaultAction
> cannot do that now because a non-local return in the #defaultAction
> method of the exception does not do what is required.
>
> If exceptions implemented #methodReturn: instead, then it might be
> possible for #defaultAction to be written like this:
>
> NonFatalIOError>>defaultAction
>
> self methodReturn: nil
>
> This is not perfect yet, and one still needs to mark the return point
> with on:do:, but maybe there's a way to write even less code here.
>
> > Yeah, I can see this in general. I'd even phrase it as "from a best
> > practices standpoint, we recommend avoiding non-local returns in
> > exception handler blocks, but if you choose to do that then using the
> > #methodReturn: method provided for that effect helps the maintainers
> of
> > the exception framework keep things working as intended because said
> > method *defines* what it means to do a non-local return in this
> > context".
> >
> > I'm fine with that.
>
> Awesome, this is in the spirit of my initial comments above.
>
> > But let's wait until we get there, and especially after we get a feel
> > for the most difficult cleanup cases. There's no need to put that
> down
> > in stone right now.
> >
> > C'mon folks, the train is at the station and I'm on board. Let's get
> > moving... ;-)
>
> :)... let's just finish getting the evidence, then we can write the
> commentary in the right place with full confidence.
>
> > I've already started in my code as you've sold me on it being something
> > to avoid when not needed. I've been holding off going beyond that as I
> > don't think we've reached agreement as to the best course of action
> > yet.
>
> I'm not convinced that the system code is beyond cleaning up... I'll
> take a look and see what.
>
> Andres.
> --
> Cuis-dev mailing list
> Cuis-dev at lists.cuis.st
> https://lists.cuis.st/mailman/listinfo/cuis-dev
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.cuis.st/mailman/archives/cuis-dev/attachments/20191105/6de3d025/attachment.htm>
More information about the Cuis-dev
mailing list