develooper Front page | perl.perl5.porters | Postings from July 2020

Re: try/catch and CLEANUP/FINALLY/&c.

Thread Previous | Thread Next
From:
Felipe Gasper
Date:
July 19, 2020 02:07
Subject:
Re: try/catch and CLEANUP/FINALLY/&c.
Message ID:
6FBF6CFC-623D-473B-91B4-88627B79C519@felipegasper.com


> On Jul 18, 2020, at 3:07 PM, Branislav Zahradník <happy.barney@gmail.com> wrote:
> 
> 
> Short summary: CLEANUP is a block's "tail call", it has nothing to do with any asynchronous event handling (like exceptions).

I was alluding to the parallel relationship between promise rejections and exceptions.

> Another aspect of CLEANUP is that it has to have access to variables it cleans, i.e. it has to share the same lexical scope.
> For example Java: finally block doesn't see variables declared inside try block (omitting AutoCloseable resources) so you have to expose its scope into the upper block anyway so usually you'll end up with wrapping block anyway.

This aspect seems common to both finally and CLEANUP blocks.

> 2) In large code blocks I could easily miss a CLEANUP by not having scrolled up. And oy, what happens if a CLEANUP is declared *midway* through such a mess?!? That’s less likely to be problematic with try/catch/finally because the indentation guides comprehension of the flow.
> 
> 
> Do you mean something like this? IMHO this code layout is easier to read and understand than one try with one final containing "if defined"
> 
> {
>     my $dbh = DBI::connect or die;
>     CLEANUP { $dbh->disconnect }
> 
>    my $sth = $dbh->prepare ...
>    $sth->execute or die;
>    CLEANUP { $sth->finish }
> 
>    while $sth->fetchrow ...
> }

What is the advantage in this case of CLEANUP versus Scope::Guard, though? Or of putting the teardown logic in a DESTROY() method (as DBI does anyway)?

If we’re not catching errors, then yeah, CLEANUP seems reasonable, but in that case it’s just adding a core syntax for Scope::Guard. Is that a significant enough thing to warrant being its own feature?

> 3) Given the overwhelming precedent of try/catch/finally, a new Perl developer--likely to come from a different language, maybe resentful of having to maintain some dot-com-era code rather than “modernizing” it to Python--will more likely grasp try/catch/finally at first glance, whereas the more esoteric CLEANUP takes extra study.
> 
> Well, overwhelming doesn't mean right, there was a time when vast majority was saying "Sun orbits Earth" 

Heliocentrism is a matter of empirical reality. No one can “prove” CLEANUP or try/catch/finally; this is mostly just speculation on what people in general will consider most useful, a large part of which is an aesthetic judgement. In that light, popular taste seems an important consideration. If the effort is to make Perl a more attractive language, bucking what’s popular seems a strange way to go about it.

That’s not to say Perl always ought to imitate other languages, particularly if there are manifest problems with the popular patterns. But when a pattern becomes a de facto standard, even in newer languages (e.g., Julia), the “burden of proof” falls on contrary models. The more widely-accepted that pattern is, moreover, the higher that “burden” rises, as the number of people whose estimations of usefulness and good design the new design decision contradicts rises also.

For example, if you read Rust’s documentation you’ll find a section on object-oriented code and why Rust does and doesn’t qualify as an object-oriented language. They embraced alternative designs, as a result of which the burden of proof falls on them to explain that decision.

> > 
> > (imho less powerful) try/catch/finally syntax can be still introduced by external module with rewriting:
> >    try TRYBLOCK catch CATCHBLOCK finally FINALLYBLOCK
> > into
> >   { CATCH CATCHBLOCK  CLEANUP FINALLYBLOCK TRYBLOCK }
> 
> Are there other languages that implement this pattern? How popular are these languages?
> 
> What do you refer to with "this" ?
> 
> Writing modules that extend core language? That's quite common in perl, I believe.

By “this” I mean the pattern you propose, e.g.:

-----
show_notification(...);
{
    CLEANUP { hide_notification };
    CATCH { report_failed... }

    attempt_...
    report_success
}
block_for_10_seconds
-----

versus how that would look in most modern languages:

-----
show_notification(...);

try {
    attempt_...
    report_success
}
catch {
    report_failed...
}
finally {
    hide_notification
}

block_for_10_seconds
-----

As to writing modules: I thought one of the goals was to fix the usability problems of implementing try/catch as a module, e.g., inability to return() from a try or catch block and the need for the trailing semicolon. Would CATCH/CLEANUP blocks facilitate having modules that address those problems?

cheers,
-Felipe
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