Using an unknown method in Perl

I find it hard to understand why Perl executes the code in braces in programs like this:

unknown_method { # some code }; 

My program:

Transaction.pm file:

 package Transaction; use strict; use warnings; use feature qw/ say /; sub transaction(&) { say 'BEGIN TRANSACTION'; eval { shift->() }; if ( $@ ) { say 'ROLLBACK TRANSACTION'; die( $@ ); # reraise error } else { say 'COMMIT TRANSACTION'; } } 1; 

file run_properly.pl:

 use feature qw/ say /; use Transaction; eval { Transaction::transaction { say "insert some data to DB"; die("KnownException") } }; warn $@ ; 

file run_wrong.pl:

 use feature qw/ say /; # I forgot to import Transaction eval { Transaction::transaction { say "insert some data to DB"; die("KnownException") } }; warn $@ ; 

Execution:

 $ perl run_properly.pl BEGIN TRANSACTION insert some data to DB ROLLBACK TRANSACTION KnownException at run_properly.pl line 6. 

and

 $ perl run_wrong.pl insert some data to DB KnownException at run_wrong.pl line 6. 

Why does Perl allow such a thing?

+4
source share
3 answers

Perl is syntactically flexible and often has more than one syntax. For example, calling methods. This is the regular and recommended syntax:

  Foo -> new (1, 2, 3); # ^-object ^- method ^- arguments 

This is the indirect syntax:

  new Foo 1, 2, 3; # ^- method ^- object ^- arguments, parens are optional 

This is all good and good, but what happens when we want to use the result of complex computation as an object with indirect musical notation?

 # set up some constructors for demonstration purposes *Foo::new = *Bar::new = sub {say "@_"}; # This obviously fails # new (rand > .5 ? "Foo" : "Bar") 1, 2, 3; 

The solution is a passive block:

 new {rand > .5 ? "Foo" : "Bar"} 1, 2, 3; 

You probably already know the dative blocks from file descriptors: print {$handles[-1]} $_ .

The dative block is executed before the method is resolved, since method resolution usually (but not in your case) depends on the type of object. However, no methods are allowed if the die s block.


Indirect notation is still pretty popular for designers, since Perl looks like C ++. However, Perl (unlike C ++) does not have a new operator: this is just an ordinary method. This flexibility may have been a bad idea, so you can "fix" it using no indirect if you are determined to do so.

+8
source

It executes the block first (since it must pass the result to Transaction::transaction ). Since you die inside this block, it never reaches Transaction::transaction .

+1
source

If you have a call like this:

  name { ... } etc. 

if name is a built-in function that takes BLOCK as its argument or a predefined routine with the & prototype, BLOCK (ie { ... } ) is not evaluated, but passed as name .

  • eg. grep { $_ > 9000 } @levels
  • this applies to run_properly.pl

Otherwise (for example, preliminary routines without a prototype or non-existent routine) the BLOCK is evaluated, then Perl searches for a routine / method called name and passes the evaluation results as an argument to name (or causes an error if name not defined).

  • this applies to run_wrong.pl case
  • you can use sub { ... } instead of { ... } if you want the BLOCK not to be evaluated in this case.
+1
source

Source: https://habr.com/ru/post/1485222/


All Articles