Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I do the same thing as reference using typeglob in perl?

$ref = \%hash;
$ref = \@hash;

How do I do the same thing as reference using typeglob in perl?

What's the exact steps perl takes to interpret $$ref{key}?

like image 697
Je Rog Avatar asked Nov 30 '22 08:11

Je Rog


1 Answers

Use the *foo{THING} syntax, which is documented in the Making References section of the perlref documentation.

A reference can be created by using a special syntax, lovingly known as the *foo{THING} syntax. *foo{THING} returns a reference to the THING slot in *foo (which is the symbol table entry which holds everything known as foo).

$scalarref = *foo{SCALAR};
$arrayref  = *ARGV{ARRAY};
$hashref   = *ENV{HASH};
$coderef   = *handler{CODE};
$ioref     = *STDIN{IO};
$globref   = *foo{GLOB};
$formatref = *foo{FORMAT};

For example:

#! /usr/bin/env perl

use strict;
use warnings;

our %hash = (Ralph => "Kramden", Ed => "Norton");
our @hash = qw/ apple orange banana cherry kiwi /;

my $ref;

$ref = *hash{HASH};
print $ref->{Ed}, "\n";

$ref = *hash{ARRAY};
print $ref->[1], "\n";

Output:

Norton
orange

As for the second part of your question, adding

print $$ref{Ralph}, "\n";

after Ed produces the expected output. The compiler generates code for this line that goes through the following sequence:

  1. Fetch the pad entry for $ref.
  2. Get $ref's thingie.
  3. Look up the key in the hash from step 2.

But don't take my word for it. To cut down the volume of output, consider a similar two-liner:

my $ref = { Ralph => "Kramden" };
print $$ref{Ralph};

Running it with a perl compiled for debugging gets us

$ debugperl -Dtls ref 
[...]
(ref:1) nextstate
    =>  
(ref:2) pushmark
    =>  *  
(ref:2) padsv($ref)              # STEP 1
    =>  *  \HV()  
(ref:2) rv2hv                    # STEP 2
    =>  *  HV()  
(ref:2) const(PV("Ralph"\0))     # STEP 3a
    =>  *  HV()  PV("Ralph"\0)  
(ref:2) helem                    # STEP 3b
    =>  *  PV("Kramden"\0)  
(ref:2) print
    =>  SV_YES  
(ref:2) leave
[...]

Note that it's slightly different for globals.

I'm not sure what your larger intent is, but there are some important caveats. Note that a typeglob represents a symbol table entry, so you can't get at lexicals this way because they live in pads, not the symbol table. For example, say you insert my @hash = ("splat"); just before the assignments to $ref in the code above. The result may surprise you.

$ ./prog 
"my" variable @hash masks earlier declaration in same scope at ./prog line 11.
Norton
orange

The behavior with respect to scalars may also be surprising.

*foo{THING} returns undef if that particular THING hasn't been used yet, except in the case of scalars. *foo{SCALAR} returns a reference to an anonymous scalar if $foo hasn't been used yet. This might change in a future release.

Tell us what you're trying to do, and we'll be able to give you specific, useful suggestions.

like image 185
Greg Bacon Avatar answered Dec 05 '22 05:12

Greg Bacon