Skip Menu |

This queue is for tickets about the Syntax-Keyword-Try CPAN distribution.

Report information
The Basics
Id: 130702
Status: resolved
Priority: 0/
Queue: Syntax-Keyword-Try

People
Owner: Nobody in particular
Requestors: leonerd-cpan [...] leonerd.org.uk
Cc:
AdminCc:

Bug Information
Severity: Wishlist
Broken in: 0.11
Fixed in:
  • 0.12
  • 0.13



Subject: Catch exception into new lexical variable
A common pattern now is try { ... } catch { my $e = $@; ... } A useful shortcut to this might be the syntax try { ... } catch my $e { ... } by taking inspiration from the lexical iterator variable in `foreach` loops. Such syntax also doesn't get in the way of whatever resolution we may eventually come to on the subject of typed dispatch, because most discussions there still agree on using parens to somehow specify how to restrict what is caught try { ... } catch my $e (SOMETHING) { ... } -- Paul Evans
On Mon Oct 14 11:36:43 2019, PEVANS wrote: Show quoted text
> try { ... } > catch my $e (SOMETHING) { ... }
I do like the symmetry with foreach for this. Syntactically it works very well. I do have some slight concerns regarding the partial symmetry though. Given how foreach works, I would possibly expect it to work without the 'my'. This of course adds scoping nightmares. Luckily this could just be an error, so confusion should be minimal. Similarly, catch without a variable would seem to imply aliasing $_ to the error. This is rather ugly of course, but it would be my expectation. And it couldn't throw an error, since it wouldn't be invalid syntax. I don't think either of these are showstoppers, but they seem worth addressing, at least in the documentation.
On Mon Oct 14 11:45:54 2019, haarg wrote: Show quoted text
> I do have some slight concerns regarding the partial symmetry though. > Given how foreach works, I would possibly expect it to work without > the 'my'. This of course adds scoping nightmares. Luckily this could > just be an error, so confusion should be minimal.
That `foreach` works without `my` by shadowing an existing (package) variable I expect is a historic baggage from the days of perl-before-5, when lexical variables didn't even exist. There's no reason we should copy that. I'm intending to allow only catch { ... } catch my $var { ... } and anything else be a syntax error. Show quoted text
> Similarly, catch without a variable would seem to imply aliasing $_ to > the error. This is rather ugly of course, but it would be my > expectation. And it couldn't throw an error, since it wouldn't be > invalid syntax. > > I don't think either of these are showstoppers, but they seem worth > addressing, at least in the documentation.
The existing semantics would remain - that the error ends up in `$@` - because that is core perl's provided behaviour. That is indeed a documentation point, just to remind users that lacking a new lexical, the error will be in `$@` as usual. I especially don't want to get into the realm of copying the error also into `$_` because that would overwrite what may be a useful value from outside the `try` block. -- Paul Evans
An initial attempt attached -- Paul Evans
Subject: rt130702.patch
=== modified file 'lib/Syntax/Keyword/Try.pm' --- lib/Syntax/Keyword/Try.pm 2019-09-07 00:19:27 +0000 +++ lib/Syntax/Keyword/Try.pm 2019-10-15 14:35:13 +0000 @@ -95,10 +95,20 @@ STATEMENTS... } +Or + + ... + catch my $var { + STATEMENTS... + } + +I<Since version NEXT.> + A C<catch> statement provides a block of code to the preceding C<try> statement that will be invoked in the case that the main block of code throws an exception. The C<catch> block can inspect the raised exception by looking -in C<$@> in the usual way. +in C<$@> in the usual way. Optionally, a new lexical variable can be +introduced to store the exception in. Presence of this C<catch> statement causes any exception thrown by the preceding C<try> block to be non-fatal to the surrounding code. If the === modified file 'lib/Syntax/Keyword/Try.xs' --- lib/Syntax/Keyword/Try.xs 2019-09-07 00:13:49 +0000 +++ lib/Syntax/Keyword/Try.xs 2019-10-15 14:35:13 +0000 @@ -245,6 +245,23 @@ return i; } +#define parse_lexvar() MY_parse_lexvar(aTHX) +static PADOFFSET MY_parse_lexvar(pTHX) +{ + char *lexname = PL_parser->bufptr; + + if(lex_read_unichar(0) != '$') + croak("Expected a lexical scalar at %s", lexname); + + if(!isIDFIRST_uni(lex_peek_unichar(0))) + croak("Expected a lexical scalar at %s", lexname); + lex_read_unichar(0); + while(isALNUM_uni(lex_peek_unichar(0))) + lex_read_unichar(0); + + return pad_add_name_pvn(lexname, PL_parser->bufptr - lexname, 0, NULL, NULL); +} + #define newSTATEOP_nowarnings() MY_newSTATEOP_nowarnings(aTHX) static OP *MY_newSTATEOP_nowarnings(pTHX) { @@ -463,9 +480,32 @@ lex_read_space(0); if(lex_consume("catch")) { - lex_read_space(0); - catch = parse_scoped_block(0); - lex_read_space(0); + PADOFFSET catchvar = 0; + I32 save_ix = block_start(TRUE); + lex_read_space(0); + + if(lex_consume("my")) { + lex_read_space(0); + catchvar = parse_lexvar(); + + lex_read_space(0); + + intro_my(); + } + + catch = block_end(save_ix, parse_block(0)); + lex_read_space(0); + + if(catchvar) { + OP *errsv_op = newGVOP(OP_GVSV, 0, PL_errgv); + OP *catchvar_op = newOP(OP_PADSV, 0); + catchvar_op->op_targ = catchvar; + + catch = op_prepend_elem(OP_LINESEQ, + /* $var = $@ */ + newBINOP(OP_SASSIGN, 0, errsv_op, catchvar_op), + catch); + } } if(lex_consume("finally")) { === modified file 't/01trycatch.t' --- t/01trycatch.t 2016-11-23 21:38:48 +0000 +++ t/01trycatch.t 2019-10-15 14:35:13 +0000 @@ -94,4 +94,14 @@ like( $caught, qr/^oopsie at /, 'exception was seen by catch{}' ); } +# catch into new lexical +{ + try { + die "caught\n"; + } + catch my $e { + is( $e, "caught\n", 'exception is caught into new lexical' ); + } +} + done_testing;
This was released in 0.12/0.13. However, ongoing design for the typed dispatch of catch suggests that actually a better design may be to follow similar syntax to subroutine signatures, and permit something such as try { ... } catch ($e isa X::SomeException) { ... } catch ($e) { anything else } Which would then replace this syntax. As a result the particular `catch my VAR` syntax is currently marked experimental and may be removed in future. Likely will be, if the above syntax idea gets implemented in its place. -- Paul Evans