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

Re: RFC 0004 - defer {} syntax

Thread Previous | Thread Next
From:
Nicholas Clark
Date:
July 2, 2021 09:45
Subject:
Re: RFC 0004 - defer {} syntax
Message ID:
20210702094450.GN11066@etla.org
On Wed, Jun 16, 2021 at 11:15:40PM +0100, Paul "LeoNerd" Evans wrote:


Yes, I really like the idea.

> ## Prototype Implementation
> 
> CPAN module `Syntax::Keyword::Defer` as already mentioned.
> 
> In addition, I have a mostly-complete branch of bleadperl (somewhat
> behind since I haven't updated it for the 5.34 release yet) at
> 
>   https://github.com/leonerd/perl5/tree/defer

It's really useful to have a prototype implementation to play with.


There were a couple of things that I noticed

## The `return` error is runtime:

$ ./perl -Ilib -E 'use feature "defer"; sub foo { defer { return; } say "Hi"}; foo()'
defer is experimental at -e line 1.
Hi
Can't "return" out of a defer block at -e line 1.


Could this be detected at compile time (the peephole optimiser? Or even the
tokeniser?) and be a runtime error?

I realise that `last` and `next` are also errors if they attempt to exit
the defer block, but loops are allowed inside defer blocks, so I doubt
that they are as easy to reliably detect at compile time.


## Error handling differs between `eval` and not.

I think that this would be the first time in perl that the behaviour between
`eval` and not eval differs. In that without eval:

$ ./perl -Ilib -E 'use feature "defer"; sub foo { defer { die "One"; } defer { die "Two" } say "Hi"}; foo(); say "Bye"'
defer is experimental at -e line 1.
defer is experimental at -e line 1.
Hi
Two at -e line 1.
One at -e line 1.


We get both exceptions to STDERR and then the process exits:


$ ./perl -Ilib -E 'use feature "defer"; sub foo { defer { die "One"; } defer { die "Two" } say "Hi"}; eval { foo() }; say "Bye"'
defer is experimental at -e line 1.
defer is experimental at -e line 1.
Hi
Bye



whereas $@ can only capture one:

$ ./perl -Ilib -E 'use feature "defer"; sub foo { defer { die "One"; } defer { die "Two" } say "Hi"}; eval { foo() }; say "\$@ is $@"; say "Bye"'
defer is experimental at -e line 1.
defer is experimental at -e line 1.
Hi
$@ is One at -e line 1.

Bye
$


and if the block exit is caused by an exception:

$ ./perl -Ilib -E 'use feature "defer"; sub foo { defer { die "One"; } defer { die "Two" } die "Three"}; eval { foo() }; say "\$@ is $@"; say "Bye"'
defer is experimental at -e line 1.
defer is experimental at -e line 1.
$@ is One at -e line 1.

Bye
$ ./perl -Ilib -E 'use feature "defer"; sub foo { defer { die "One"; } defer { die "Two" } die "Three"}; foo(); say "\$@ is $@"; say "Bye"'
defer is experimental at -e line 1.
defer is experimental at -e line 1.
Three at -e line 1.
Two at -e line 1.
One at -e line 1.


it's consistent - the last error encountered is in $@. But errors get
eaten.

I'm struggling to suggest a better solution. I *think* that possibly $@
ought to be the *first* error encountered. As Klortho glibly put it:

#11916 Always ignore the second error message unless the meaning is obvious

but what's bugging me is that the second (or subsequent errors) might be
fallout from the problem that caused the first exception and error message,
but if that error message is lost (and not reported) it could be rather hard
to figure out that actual problem.


Do we also need to create a variable @@ which exposes the stack of exceptions
encountered? (With $@ set to one of them, last as you currently have it,
first as I'm suggesting, and unchanged for existing problematic situations,
such as exceptions firing in DESTROY)

Nicholas Clark




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