Beefy Boxes and Bandwidth Generously Provided by pair Networks
Come for the quick hacks, stay for the epiphanies.
 
PerlMonks  

What delete from symbol table really means? (Deleting typeglob of a specified package)

by Discipulus (Canon)
on Feb 16, 2015 at 09:39 UTC ( [id://1116851]=perlquestion: print w/replies, xml ) Need Help??

Discipulus has asked for the wisdom of the Perl Monks concerning the following question:

Hello monks,

In my learning curve, i touched symbol table for the second time. I read Of Symbol Tables and Globs and at the end i was sure to have understood. Now i'm reading Mastering Perl and precisely a chapter dedicated to Symbol table and typeglobs (chapter 8). There is an example that left me full of doubts; here i propose you a semplified version:
#!/usr/bin/perl package Foo { $n = 10; show_foo( "After assignment" ); delete $Foo::{'n'}; show_foo( "After delete" ); sub show_foo { print "-" x 10, $_[0], "-" x 10, "\n"; print "\$n is $n\n"; foreach my $name ( keys %Foo:: ) { print "$name\n"; } } }#end of package Foo ##OUT ----------After assignment---------- $n is 10 show_foo n ----------After delete---------- $n is 10 show_foo
The main question is: why this $n is still here with his well round value? The entry in the symbol table is gone the variable itself no!
The output of the example is correct but not explained by the book and (as ysth noticed see page 130 seems i'm not the only one to be confused).

When i asked this into the chat, the kind monk ysth pointed me to the first clearly stated sentence about the matter: an answer from ysth on another site.

That answer contains others choking examples about the matter:
$n = 123; delete $::{n}; eval '$n=456'; print $n; eval 'print $n'; #OUT 123456
and
$n = 123; sub get_n { $n } BEGIN { delete $::{n} } $n = 456; print get_n(); print $n; #OUT 123456
So there is a way to safely access and modify (so delete too) a specified entry in the symbol table or a specified slot in it (using the so called *foo{THING} notation). There is a gently way? or I need to nuke the package at whole? as in:
#!/usr/bin/perl use Symbol qw(delete_package); package Foo { $n = 10; show_foo( "After assignment" ); sub show_foo { print "-" x 10, $_[0], "-" x 10, "\n"; print "\$n is $n\n"; foreach my $name ( keys %Foo:: ) { print "$name\n"; } } }#end of package Foo delete_package('Foo'); # package Foo again package Foo{ show_foo( "After delete" ); } #OUT ----------After assignment---------- $n is 10 show_foo n Undefined subroutine & called at ...

The Symbol of the core module have intimidating BUGS section about the delete_package call.

Thanks for the attention.

L*
There are no rules, there are no thumbs..
Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.
  • Comment on What delete from symbol table really means? (Deleting typeglob of a specified package)
  • Select or Download Code

Replies are listed 'Best First'.
Re: What delete from symbol table really means? (Deleting typeglob of a specified package)
by LanX (Saint) on Feb 16, 2015 at 14:25 UTC
    short

    You only deleted a stash entry pointing to the glob, not the glob which continues to exist as long as it is referenced in code.

    long

    A typeglob is a kind of hash with 6 fixed slots holding different data types² !

    The scalar $n is the value referenced in the scalar slot of of the glob *n ¹

    Think of a stash as a HoH  $pck{globname}{SCALAR} = \ 'value'

    And like all Perl data *n is a C structure somewhere in memory and can be retrieved by its reference GLOBREF = \*n.

    A symbol table is a hash holding names and references of such typeglobs.

    Eg in your case

     %Foo:: = ( ..., "n"=> GLOBREF, ... )

    The code print $n internally compiles to something like  print GLOBREF->{SCALAR} where GLOBREF was looked up in the stash at compile time and hardcoded into the OP-codes.

    simplified analogy

    globs and stashes are confusing, I tried to translate what is happening to HoHs.

    Maybe that makes it clearer

    BEGIN { # at compile time %stash =(); # 'package stash' $stash{n}{SCALAR} =undef; # $n first use ( i.e. our-declaration ) $n_glob = $stash{n}; # exists only hardcoded } # at runtime: execute compiled op-codes $n_glob->{SCALAR}=123; delete $stash{n}; print $n_glob->{SCALAR}; # > 123

    So deleting the Stash entry didn't delete the underlying glob (it's still referenced)

    Update: You only sabotaged introspection at run time or further compilations with eval('print $n') .

    Cheers Rolf

    PS: Je suis Charlie!

    update

    ¹)

    DB<104> $n=123 => 123 DB<105> *n{SCALAR} => \123

    ²) i.e. refs to SCALAR, ARRAY, HASH, CODE, IO, GLOB, FORMAT see perlref

      Though I have to admit that it's a bit confusing that a typeglob keeps track of it's original package and name, even after it isn't listed there anymore.

      lanx@lanx-1005HA:~/pm$ cat tst_glob.pl $\="\n"; $n=123; $gr=\*n; print *n{PACKAGE}," :: ",*n{NAME}," = ", ${*n{SCALAR}}; delete $main::{n}; print *{$gr}{PACKAGE}," :: ",*{$gr}{NAME}," = ", ${*{$gr}{SCALAR}}; lanx@lanx-1005HA:~/pm$ perl tst_glob.pl main :: n = 123 main :: n = 123

      Cheers Rolf

      PS: Je suis Charlie!

        see Symbol Symbol::delete_package
        # # of Safe.pm lineage # sub delete_package ($) { my $pkg = shift; # expand to full symbol table name if needed unless ($pkg =~ /^main::.*::$/) { $pkg = "main$pkg" if $pkg =~ /^::/; $pkg = "main::$pkg" unless $pkg =~ /^main::/; $pkg .= '::' unless $pkg =~ /::$/; } my($stem, $leaf) = $pkg =~ m/(.*::)(\w+::)$/; my $stem_symtab = *{$stem}{HASH}; return unless defined $stem_symtab and exists $stem_symtab->{$leaf +}; # free all the symbols in the package my $leaf_symtab = *{$stem_symtab->{$leaf}}{HASH}; foreach my $name (keys %$leaf_symtab) { undef *{$pkg . $name}; } # delete the symbol table %$leaf_symtab = (); delete $stem_symtab->{$leaf}; }
Re: What delete from symbol table really means? (Deleting typeglob of a specified package)
by Anonymous Monk on Feb 16, 2015 at 10:54 UTC
    The main question is: why this $n is still here with his well round value? The entry in the symbol table is gone the variable itself no!
    It seems you think that the notation $n is a shorthand for something like $symbol_table_hash{n}. You're used to how Perl's hashes work. But, as you see, symbol tables are special, they're used at compile time and at run time Perl doesn't even look if key n is present in the symbol table (if it can avoid that). Why? For efficiency, of course. Perl COULD always look up things in symbol tables, in principle (at least I don't see why it couldn't). But it would be slower.

    Also, the value 10 is not "inside" the symbol table hash. 10 is just somewhere in computer memory; the symbol table has information about how to find 10 (has the address of 10). Perl uses that information (the address) when it's compiling the code. When the code runs, the address is "compiled into" show_foo, and show_foo uses it directly, without fetching it from the symbol table.

    That answer contains others choking examples about the matter:
    $n = 123; delete $::{n}; eval '$n=456'; print $n; eval 'print $n';
    Think of it this way: Perl only looks up the symbol table at run time if it must. So, for example, when you eval a string, Perl has to consult the symbol table, because at compile time 'print $n' was just a string, not code. OTOH, print $n (without quotes) was code, so the compiler could figure it out, and replace $n with its direct address in memory.

    use feature 'say'; package Foo { our $n = 10; show_foo("After assignment"); delete $Foo::{'n'}; show_foo("After delete"); sub show_foo { say shift; say '$n => ', $n; say '$Foo::n => ', $Foo::n; say '$Foo::{n} => ', $Foo::{n}; say; } }

    Output:
    $n => 10 $Foo::n => 10 $Foo::{n} => *Foo::n After delete $n => 10 $Foo::n => 10 $Foo::{n} =>
    As you can see, it does remove the typeglob, it's just that 10 is untouched, and show_foo still knows where it is. $n and $Foo::n are special and resolved when compiling show_foo.
Re: What delete from symbol table really means? (Deleting typeglob of a specified package)
by Anonymous Monk on Feb 16, 2015 at 13:28 UTC

    You can undef the glob before deleting the symbol table element.undef $::{n}; delete $::{n};

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1116851]
Approved by Athanasius
Front-paged by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others drinking their drinks and smoking their pipes about the Monastery: (4)
As of 2024-04-19 04:49 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found