venerdì 12 maggio 2017

Postfix dereference operator

Starting from Perl 5.20 it is allowed to use a postfix dereference notation, first as an explicit feature, and since Perl 5.24 it is enabled by default.
The postfix dereference notation allows you to use the arrow operator -> on a reference (as often used when combined with references) specifying the type of the deferencing you want to. Types are indicated by their well know sigils, so for instance a $ means a scalar, a @ an array, & is for a subroutine, % for an hash and * for a typeglob. The sigil on the right of the arrow operator is enhanced by a star, so it really becomes type and *, as in $*. In the special case of arrays and hashes the star can be dropped in favor of a slicing operator, e.g., the square brackets.
The following is a sample program that prints out the values of an array using full access (->@*) and slicing (->@[]):

#!env perl
use v5.24;

my @array = ( 'a' .. 'z' );
my $ref   = \@array;
say "Here comes the array @{ $ref }";
say "And post dereferences is $ref->@*";

say "Here comes a slice @{ $ref }[ 0 .. 5 ]";
say "And using it as post dereference is $ref->@[ 0 .. 5 ]";
As you can see, $ref->@* is the equivalent of @{ $ref }, while $ref->@[] is the same as @{ $ref }[]. The same applies to hash references.
Code and subroutine references are a little more controversial, at least to my understanding of references. First of all there is only the star operator, so ->&*, and the behavior is such that $ref->&* is the same as &{ $ref }. This makes me think there is no short way of passing method arguments thru a postfix deference, as the following code demonstrates:

#!env perl
use v5.24;

my $sub_ref = sub { say "Hello sir @_ !" };
$sub_ref->( 'Luca' );         # Hello sir Luca !
&{ $sub_ref }( 'Luca' );      # Hello sir Luca !
$sub_ref->&* ;                # Hello sir  !
{ $sub_ref->&* }( 'Luca' );   # Hello sir  !
&$sub_ref( 'Luca' );          # Hello sir Luca !

If you try to pass arguments in any way to the ->&* dereferencing, you got either a compile time error or a code that does not what you expect:

{ $sub_ref->&>* }( 'Luca ');   # Hello sir  !
$sub_ref->&( 'Luca' );        # syntax error at tmp/ line 19, near "->&"
$sub_ref->&*( 'Luca' );       # syntax error at tmp/ line 20, near "&*( "
{ $sub_ref->& }( 'Luca ');    # syntax error at tmp/ line 21, near "->&"

The only catch-all way of passing arguments, as suggested on, is to use the @_, so I suggest to localize it:

  local @_ = qw( Luca ); 
  $sub_ref->&*; # Hello sir Luca ! 

I must admit this is a little too much for my poor brain in order to efficiently use the references, so if anyone has something to comment is truly welcome!
Now, back to the main topic, it seems to me that the postfix dereference notation is a way of managing reference more like objects, at least it reminds me a kind of as_xx methods (yes, Ruby-ers, I'm looking at you). If we read the arrow operator like as and the type on sigil on the right as the type name, we have that, for instance:
  • $ref->$* is $ref as scalar;
  • $ref->@* is $ref as array or $ref>@[] becomes $ref as array slice
and so on. While I'm pretty sure this is not the real meaning of this notation, it is sure most readable than the "usual" one, where we have the type on the left and the reference on the right (or better in the middle), as in @$ref or @{ $ref }.

Nessun commento: