Search code examples
perlreferencetypeglob

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}?


Solution

  • If you're asking how you get a reference to a type glob, it's just:

    my $ref = \*symbol_name_here;
    

    For a "literal name" of the symbol, (that is where you type in the exact name of the symbol), and not a variable. But, you can do this:

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

    for a variable symbol. However, the above works with strict and the easier one below doesn't:

    my $ref = \*{$symbol_name};
    

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

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

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

    Once you have the symbol ref, to get the slot, you have to deference the reference, so perl does not think you're trying to use it as a hash, like so.

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

    Another Take

    I put your two ideas together in a different way. If you have a symbol table reference, you can get the HASH slot and that is a reference just like any other reference to a hash. So you can do the following.

    Either

    *hash{HASH}->{key}
    

    Or

    ${ *hash{HASH} }{key}
    

    will work. These are safer, though

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

    If you want to do this not with a direct entry, but a reference into the table, you would do the following:

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

    NOTE: %hash absolutely needs to be a package variable. Only package variables reside in the symbol table (so only subs and @ISA and Exporter variables tend to be in modern symbol tables). Lexical variables (those declared my) reside in the "pad".


    UPDATE:

    • I have gotten away from using Symbol so much. Curiously, even though it is core, it seems non-standard in the way Perlers do--and see--things. Instead, I use the direct way 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 the *STDERR{IO} idiom for a glob file handle reference. In modern Perl, these are usually objects.

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