develooper Front page | perl.perl5.porters | Postings from January 2021

Re: Adding a try/catch syntax to Perl

Thread Previous | Thread Next
From:
Paul "LeoNerd" Evans
Date:
January 27, 2021 17:58
Subject:
Re: Adding a try/catch syntax to Perl
Message ID:
20210127175836.2ac04ba4@shy.leonerd.org.uk
On Wed, 27 Jan 2021 12:54:48 +0100
Branislav ZahradnĂ­k <happy.barney@gmail.com> wrote:

> I will repeat my objections against try/catch syntax from code
> maintenance point of view (assuming that maintenance is 80% of code
> base life-cycle)

And I will repeat my replies to them.

> try / catch is type of construct where usually huge chunk of code
> comes before smaller one.
> It's common rule to put smaller parts ahead of larger parts in if
> statement, so why not to do same with exception handing?

See my comments I made to Philip Brenan about "Garden Path Sentences";
to wit:

|> One of the points of upfront try/catch notation is that it alerts the
|> reader, when scanning down the code in the usual top-to-bottom
|> fashion, that something fun is happening with respect to exception
|> handling. Otherwise, you can be mislead as to the nature of the
|> behaviour if you get a long piece of code that reads
|> 
|>   {
|>     ... # 50 lines of code here
|>   } fail {
|>     ...
|>   }
|> 
|> once you skip past those 50 lines and realise what was going on.
|> 
|> In the sphere of natural languages there is the concept of a "garden
|> path sentence"; to quote Wikipedia on the subject:
|> 
|>   A garden-path sentence is a grammatically correct sentence that
|>   starts in such a way that a reader's most likely interpretation
|>   will be incorrect; the reader is lured into a parse that turns out
|>   to be a dead end or yields a clearly unintended meaning. 
|>     -- https://en.wikipedia.org/wiki/Garden-path_sentence
|> 
|> "The horse raced past the barn fell." has always been my favourite of
|> these. As perhaps you can tell by reading it aloud, it causes some
|> mental upset when you have to reparse what it meant.
|> 
|> I would consider it rude of a language to encourage programmers to
|> write such programs, even if we can theoretically parse them.
|> 
|> (It is also for this reason I considered but rejected a Raku-style
|> embedded CATCH {} phaser block inside a regular one.)

That verymuch applies here too.

> You are working on FINALLY block. So implement CATCH (condition)
> BLOCK same way (valid since declaration).
> At the end result code will be:
> - declare how to handle unexpected behaviour (aka: install handler)
> - do something

FINALLY blocks are in quite a different category; and indeed the very
difference is why I decided not to implement them as try/finally.

The thing with try/catch is that the "try-ness" of the first block
*alters* the way that exceptions work inside it. The code of the try
block now has a different meaning; it is effectively a filter on the
kind of result it might yield. Whereas by attaching a FINALLY there is
no difference in meaning, no adjustment.. the FINALLY block is merely a
passive observer of the code having reached a certain position.

> It will be also nice to have conditional exception handling (including
> FINALLY):
>     CATCH (connection error) { sleep 10; redo; } if $retry_allowed;

Ambiguous. If the CATCH is conditional, does it make the
exception-filtering properties of its effect on the containing block
conditional as well?

Also, that particular syntax would imply that CATCH blocks now require
a terminating semicolon, otherwise how do we parse

  CATCH (thing) { do stuff }

  if($cond) { other code }

(that is also the reason for which conditional FINALLY blocks aren't
possible)

> and last but not least: you can easily implement less expressive
> variant (try/catch/finally) using FINALLY / CATCH blocks
> 
> Example (pseudo code):
> sub q {
>    CATCH (DBI::Connection::Error) { ... }
>    my $dbh = connect;
>    FINALLY { $dbh->disconnect }
> 
>    CATCH (no rows selected exception) { return; }
>    CATCH (sql exception) { $log->log; redo BLOCK; }
> 
>    BLOCK:
>      $dbh->do (...);
> }

The presence of multiple CATCHes inside a single block now yields
further questions. Do they only take effect from that point onwards,
not covering the lines above? Can they replace each other, or do they
all accumulate and stack up?

These kinds of questions don't apply to FINALLY, because the entire
point is that they stack up. Them all being passive observers of simply
"that block has now finished" means that it's clear what happens when
there's multiple of them. Much less clear to see what multiple CATCHes
with overlapping specifications would mean.


Overall here I really want to appeal to the fact that CPAN already has
*many* many try/catch modules, of which the popular ones appear in
large amounts of other code as dependencies. It seems in this case that
the market has spoken for what it is they want. I don't want to spend
months (or years) inventing new mistakes in core, when we can instead
adopt the tried-and-tested ideas from years of CPAN-based
experimentation. That was always what the `PL_keyword_plugin` mechanism
was for, which has allowed many of these modules in the first place.

-- 
Paul "LeoNerd" Evans

leonerd@leonerd.org.uk      |  https://metacpan.org/author/PEVANS
http://www.leonerd.org.uk/  |  https://www.tindie.com/stores/leonerd/

Thread Previous | Thread Next


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About