in reply to Assigning to the CODE slot of a GLOB whose REF is held in a lexical?

Thanks guys. You poked me in the right direction.

I knew I had this work before. I turns out that if the base GLOB has something assigned to the CODE slot before you take the reference to it, then you can use any of:

  1.  *{ *$glob } = sub{ "Anon 4: $_[ 0 ]" };
  2.  *$glob = sub{ "Anon 5: $_[ 0 ]"; };
  3.  *{ $glob } = sub{ "Anon 6: $_[ 0 ]"; };

And they all work.

But if the original GLOB has nothing assigned to the code slot, nothing works. Seems like a bug to me?

#! perl -slw use strict; no warnings 'uninitialized'; ## suppress expected warnings ## ASSIGN TO CODE TO THE GLOB FIRST AND... *GLOB = sub { "Anon 1: $_[ 0 ]" }; my $glob = do{ local *GLOB = sub { "Anon 2: $_[ 0 ]" }; \*GLOB }; print "\$glob = ", $glob; print "$_ => ", *$glob{ $_ }, ' => ', $_ eq 'SCALAR' ? ${ *$glob } : $_ eq 'ARRAY' ? join ', ', @{ *$glob } : $_ eq 'HASH' ? join ', ', %{ *$glob } : $_ eq 'CODE' ? &{ *$glob } : 'n/a' for qw[ SCALAR ARRAY HASH CODE IO FORMAT ]; print "\n-------\n\n Now assign some values to the slots\n"; ${ *$glob } = 'A scalar'; @{ *$glob } = qw[ an array ]; %{ *$glob } = qw[ This is a hash ]; print $glob; print "$_ => ", *$glob{ $_ }, ' => ', $_ eq 'SCALAR' ? ${ *$glob } : $_ eq 'ARRAY' ? join ', ', @{ *$glob } : $_ eq 'HASH' ? join ', ', %{ *$glob } : $_ eq 'CODE' ? &{ *$glob } : 'n/a' for qw[ SCALAR ARRAY HASH CODE IO FORMAT ]; ## THIS WORKS NOW *{ *$glob } = sub{ "Anon 4: $_[ 0 ]" }; print "\n\nAfter \*{ *\$glob } = sub{ ... }: ", $glob; print $glob; print "$_ => ", *$glob{ $_ }, ' => ', $_ eq 'SCALAR' ? ${ *$glob } : $_ eq 'ARRAY' ? join ', ', @{ *$glob } : $_ eq 'HASH' ? join ', ', %{ *$glob } : $_ eq 'CODE' ? &{ *$glob } : 'n/a' for qw[ SCALAR ARRAY HASH CODE IO FORMAT ]; ## SO DOES THIS *$glob = sub{ "Anon 5: $_[ 0 ]"; }; print "\n\nAfter *\$glob = sub{ ... }: ", $glob; print $glob; print "$_ => ", *$glob{ $_ }, ' => ', $_ eq 'SCALAR' ? ${ *$glob } : $_ eq 'ARRAY' ? join ', ', @{ *$glob } : $_ eq 'HASH' ? join ', ', %{ *$glob } : $_ eq 'CODE' ? &{ *$glob } : 'n/a' for qw[ SCALAR ARRAY HASH CODE IO FORMAT ]; ## AND SO DOES THIS! *{ $glob } = sub{ "Anon 6: $_[ 0 ]"; }; print "\n\nAfter \*{ \$glob } = sub{ ... }: ", $glob; print $glob; print "$_ => ", *$glob{ $_ }, ' => ', $_ eq 'SCALAR' ? ${ *$glob } : $_ eq 'ARRAY' ? join ', ', @{ *$glob } : $_ eq 'HASH' ? join ', ', %{ *$glob } : $_ eq 'CODE' ? &{ *$glob } : 'n/a' for qw[ SCALAR ARRAY HASH CODE IO FORMAT ]; __END__ [17:06:27.35] P:\test>globs $glob = GLOB(0x1824398) SCALAR => SCALAR(0x182435c) => ARRAY => => HASH => => CODE => CODE(0x1824368) => Anon 1: IO => => n/a FORMAT => => n/a ------- Now assign some values to the slots GLOB(0x1824398) SCALAR => SCALAR(0x182435c) => A scalar ARRAY => ARRAY(0x224fe4) => an, array HASH => HASH(0x224ff0) => a, hash, This, is CODE => CODE(0x1824368) => Anon 1: IO => => n/a FORMAT => => n/a After *{ *$glob } = sub{ ... }: GLOB(0x1824398) GLOB(0x1824398) SCALAR => SCALAR(0x182435c) => A scalar ARRAY => ARRAY(0x224fe4) => an, array HASH => HASH(0x224ff0) => a, hash, This, is CODE => CODE(0x184d4dc) => Anon 4: IO => => n/a FORMAT => => n/a After *$glob = sub{ ... }: GLOB(0x1824398) GLOB(0x1824398) SCALAR => SCALAR(0x182435c) => A scalar ARRAY => ARRAY(0x224fe4) => an, array HASH => HASH(0x224ff0) => a, hash, This, is CODE => CODE(0x184d668) => Anon 5: IO => => n/a FORMAT => => n/a After *{ $glob } = sub{ ... }: GLOB(0x1824398) GLOB(0x1824398) SCALAR => SCALAR(0x182435c) => A scalar ARRAY => ARRAY(0x224fe4) => an, array HASH => HASH(0x224ff0) => a, hash, This, is CODE => CODE(0x184d7f4) => Anon 6: IO => => n/a FORMAT => => n/a

Examine what is said, not who speaks.
"Efficiency is intelligent laziness." -David Dunham
"Think for yourself!" - Abigail        "Time is a poor substitute for thought"--theorbtwo
"Memory, processor, disk in that order on the hardware side. Algorithm, algorithm, algorithm on the code side." - tachyon

Replies are listed 'Best First'.
Re^2: Assigning to the CODE slot of a GLOB whose REF is held in a lexical?
by revdiablo (Prior) on Nov 17, 2004 at 07:35 UTC
    if the original GLOB has nothing assigned to the code slot, nothing works.

    That's not the behavior I'm seeing. This code works fine all by itself:

    my $globref = \*GLOB; *$globref = sub { print "Glob\n" }; GLOB();

    It prints "Glob\n" just as I'd expect, even though the glob had nothing at all when the reference was taken. The problem comes from the use of local in the do block when creating the globref.

    A globref created from a localized glob seems to lose some of its magic when the block exits. Then, when you try to assign something to one of its slots, the whole reference gets overwritten by what you assigned, not just the particular slot:

    my $globref = \do { local *GLOB }; print $globref, "\n"; # prints GLOB(0x.......) *$globref = 1; print $globref, "\n"; # prints SCALAR(0x.......)

    I don't know if this is a bug, but it's certainly surprising. I'd expect local to clobber the values from the globref when the block exits, but making the globref itself act differently is kind of strange.

      You're explicitly overwriting the globref with a scalar. <P.You need to use the right syntax to assign to the SCALAR slot of the referenced glob.

      [ 7:53:35.32] P:\test>perl -l my $globref = \do { local *GLOB }; print $globref; ## Assign to the SCALAR slot in the glob referenced by $globref ${ *$globref } = 123456789; print $globref; ## Still a GLOB print ${ *$globref }; ## Contains our value ## This is where the trouble comes in. *$globref = sub{ print 'test' }; print ${ *$globref }, $/, &{ *$globref }; ^Z GLOB(0x224fc8) GLOB(0x224fc8) 123456789 Not a GLOB reference at - line 13.

      However, I did just discover this.

      [ 7:56:55.39] P:\test>perl -l my $globref = do { local *GLOB; \*GLOB; }; print $globref; ## Assign to the SCALAR slot in the glob referenced by $globref ${ *$globref } = 123456789; print $globref; ## Still a GLOB print ${ *$globref }; ## Contains our value ## This is where the trouble comes in. *$globref = sub{ print 'test' }; print ${ *$globref }, $/, &{ *$globref }; ^Z GLOB(0x1824284) GLOB(0x1824284) 123456789 test 123456789 1

      If I return the reference to the localised GLOB from with the do block, then everything works fine, without the need to pre-assign something to the actual GLOB before hand.

      I'm pretty sure that I picked up on the idiom of

      my $globref = \ do{ local *GLOB; };

      from a usually reliable (and wizardly:) source, but I'll need to check that.

      As I understand it, localising the GLOB effectively give you access to a new (anonymous) typeglob ensuring that if the code is called multiple times, you get a new once each time, without needing to go the Symbol route of creating sequence numbered globs in a special namespace.

      However, my understanding may well be wrong. This could just be what I assumed the do local construct was doing. Hmmm. Off to try and relocate some sources and refresh my memory.

        As a foreward, I hope you don't get the wrong idea about my replies. I'm not trying to beat the point into the ground, I'm just trying to figure out exactly what's going on. If you're getting tired of this thread, feel free to ignore my reply.

        You're explicitly overwriting the globref with a scalar. <P.You need to use the right syntax to assign to the SCALAR slot of the referenced glob.

        Well, this doesn't overwrite the glob reference with a scalar reference:

        my $globref = \*GLOB; *$globref = 1; print $globref, "\n"; # prints GLOB(0x.......)

        But you're right that I'm not using the right syntax. I really meant to do this (which works as expected):

        my $globref = \*GLOB; *$globref = \1; print $globref, "\n"; # prints GLOB(0x.......)

        Compared to this (which overwrites the entire glob reference, strangely):

        my $globref = \do { local *GLOB }; *$globref = \1; print $globref, "\n"; # prints REF(0x.......)
        If I return the reference to the localised GLOB from with the do block, then everything works fine

        Hmm, I thought about trying this, but got distracted. I'm glad you thought to try it for me. ;-) Perhaps it's something with the way local is returning the glob?

        As I understand it, localising the GLOB effectively give you access to a new (anonymous) typeglob

        That's what I thought when I first saw you use the idiom, but now I'm not sure what's going on. If you find out, please let me know. This is very curious. :-)