How do I do the same as a link using typeglob in perl?

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

How to do the same thing as a link using typeglob in perl?

What are the exact perl steps for interpreting $$ref{key} ?

+4
source share
4 answers

If you ask how to get a reference to the glob type, simply:

 my $ref = \*symbol_name_here; 

For the "literal name" of this character (that is, where you enter the exact name of the character), not a variable. But you can do it:

 my $ref = Symbol::qualify_to_ref( $symbol_name ); 

for a variable symbol. However, the above works with strict , and the simpler one below:

 my $ref = \*{$symbol_name}; 

One of the nice things about Symbol::qualify* is that it treats package names as a second variable. So that...

 my $sref = Symbol::qualify_to_ref( $symbol_name, $some_other_package ); 

does the same as \*{$some_other_package.'::'.$symbol_name} , and works with strict .

Once you have the ref character in order to get this slot, you must respect the link, so perl doesn't think you're trying to use it as a hash, for example.

 my $href = *{ $sref }{HASH}; my $code = *{ $sref }{CODE}; my $arref = *{ $sref }{ARRAY}; my $io = *{ $sref }{IO}; 

Another Take

I combined your two ideas in a different way. If you have a link to a symbol table, you can get a HASH slot, and this is a link, like any other hash link. Therefore, you can do the following.

Or

 *hash{HASH}->{key} 

or

 ${ *hash{HASH} }{key} 

will work. It's safer though

 ( *hash{HASH} || {} )->{key}; ${ *hash{HASH} || {} }{key}; 

If you want to do this not with a direct record, but with a link to the table, you must do the following:

 my $ref = \*hash; my $value = *{ $ref }{HASH} && *{ $ref }{HASH}->{key}; 

NOTE. %hash absolutely must be a package variable. Only package variables are in the symbol table (so only subs and @ISA and Exporter variables are usually found in modern symbol tables). Lexical variables (declared by my ) are in the "pad" .


UPDATE:

  • I have not used Symbol so much. Curiously, although this is the core, it seems unconventional in how Perler does - and sees - things. Instead, I use the direct path in what I call "no blocks" as localized as I can make them.

     # All I want is one symbol. # Turn strict-refs off, get it, turn it back on. my $symb = do { no strict 'refs'; \*{$symbol_name} }; 

    OR

     { no strict 'refs'; *{$package_name.'::'.$symbol_name} = $sub_I_created; ... # more reckless symbol table mucking... } 
  • I almost always use idiom *STDERR{IO} to reference the glob file descriptor. In modern Perl, these are usually objects.

     my $fh = *STDERR{IO}; say blessed( $fh ); # IO::File $fh->say( 'Some stuff' ); 
+6
source

Use the syntax *foo{THING} , which is described in the Linking section of the perlref documentation.

A link can be created using special syntax, lovingly known as the syntax *foo{THING} . *foo{THING} returns a reference to the THING slot in *foo (which is an entry in the character table that contains everything called foo ).

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

For instance:

 #! /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 

Regarding the second part of your question, adding

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

after Ed produces the expected result. The compiler generates code for this line, which goes through the following sequence:

  • Retrieve the pad entry for $ref .
  • Get $ref thingie.
  • Look at the key in the hash from step 2.

But do not take my word for it. To reduce output, consider a similar two-line layer:

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

Running with 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
 [...] 

Please note that it is slightly different for global ones.

I'm not sure what your big intentions are, but there are some important reservations. Note that typeglob is an entry in the form of a symbol table, so you cannot lie like that because they live in pads, not in a symbol table. For example, let's say you type my @hash = ("splat"); just before assigning $ref in the above code. The result may surprise you.

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

Scalar behavior may also be unexpected.

*foo{THING} returns undef if this particular THING has not yet been used, except for scalars. *foo{SCALAR} returns a link to an anonymous scalar if $foo has not yet been used. This may change in a future version.

Tell us what you are trying to do, and we can give you specific useful suggestions.

+9
source

I donโ€™t think you can do the same with typeglobs, as you can do with links (for example, lexical variables never include the type glob). What do you want to achieve in the end?

As for $$ref{key} , perl is executed as follows:

  • first $ says scalar returns
  • the presence of a variable after the sigil indicates that this variable should have a link
  • {...} indicates that $ref should be a hash reference
+1
source

Perl is wonderful and cool experimental:

Try:

  perl -MO=Terse -e' $ref = \%hash; $ret = $$ref{key}' 

or

  perl -MO=Debug -e' $ref = \%hash; $ret = $$ref{key}' 

and everything will be revealed. If you have debugging Perl, you can even do:

  perl -Dt -e'$ref = \%hash; $ret = $$ref{key}' 
0
source

All Articles