Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Strange perl code - looking for explanation

I know a little bit perl, but not enough deeply to understand the next.

Reading perldelta 5.18 i found the next piece of code what is already disabled in 5.18. Not counting this, still want understand how it's works.

Here is the code and in the comments are what i understand

%_=(_,"Just another "); #initialize the %_ hash with key=>value   _ => 'Just another'
$_="Perl hacker,\n";    #assign to the $_ variable with "Perl..."
s//_}->{_/e;            # darkness. the /e - evauates the expression, but...
print

it prints:

Just another Perl hacker,

I tried, the perl -MO=Deparse and get the next

(%_) = ('_', 'Just another ');   #initializing the %_ hash
$_ = "Perl hacker,\n";           # as above
s//%{'_';}/e;                    # substitute to the beginning of the $_ - WHAT?
print $_;                        # print the result
japh syntax OK

What is strange (at least for me) - running the "deparsed" code doesn't gives the original result and prints:

1/8Perl hacker,

I would be very happy:

  1. if someone can explain the code, especially if someone could write an helper code, (with additional steps) what helps me understand how it is works - what happens.
  2. explain, why the deparsed code not prints the original result.

What means the %{'_';} in the deparsed code?

like image 661
jm666 Avatar asked Jun 01 '13 18:06

jm666


1 Answers

The code actually executed by the substitution operator is probably actually something like

my $code = "do { $repl_expr }";

So when the replacement expression is _}->{_, the following is executed:

do { _}->{_ }

_ simply returns the string _ (since strict is off), so that's the same as

do { "_" }->{_}

which is the same as

"_"->{_}

What you have there is a hash element dereference, where the reference is a symbolic reference (i.e. a string rather than an actual reference). Normally forbidden by strict, here's an example of a symbolic reference at work:

%h1 = ( id => 123 );
%h2 = ( id => 456 );
print "h$_"->{id}, "\n"
   for 1..2;

So that means

"_"->{_}    # Run-time symbol lookup

is the same as

$_{_}       # Compile-time symbol lookup

A similar trick is often used in one-liners.

perl -nle'$c += $_; END { print $c }'

can be shortened to

perl -nle'$c += $_; }{ print $c'

Because the code actually executed when -n is used is obtained from something equivalent to

my $code = "LINE: while (<>) { $program }";

%{'_';}

is a very weird way to write

%{'_'}

which is a hash dereference. Again, the reference here is a symbolic reference. It's equivalent to

%_

In scalar context, hash current returns a value that reports some information about that hash's internals (or a false value if empty). There's been a suggestion to change it to return the number of keys instead.

like image 162
ikegami Avatar answered Sep 20 '22 20:09

ikegami