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

I swear I've had this work before, but not today. I have a GLOBREF held in a lexical scalar. I can assign new values to the GLOBs SCALAR, ARRAY & HASH slots, independantly of each other just fine.

Now I need to add or modify the CODE slot, without affecting the existing values in the other slots. I've tried various syntaxes, including some stupid ones, but nothing work?

#! perl -slw use strict; no warnings 'uninitialized'; ## supress expected warnings ## Place a globref into a lexical scalar my $glob = \ do{ local *GLOB; }; print "\$glob = ", $glob; print "$_ => ", *$glob{ $_ }, ' => ', $_ eq 'SCALAR' ? ${ *$glob } : $_ eq 'ARRAY' ? join ', ', @{ *$glob } : $_ eq 'HASH' ? join ', ', %{ *$glob } : # $_ eq 'CODE' ? &{ *$glob } : ## fatal as CODE slot i +s empty 'n/a' for qw[ SCALAR ARRAY HASH CODE IO FORMAT ]; print "The scalar slot is initialised to point to undef(?) '${ *$glob +}'"; 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 ]; ## HOW TO ASSIGN A VALUE TO THE CODEREF (not overwriting all the other + slots!) ## This attempts to invoke the sub # &{ *$glob } = sub{ print 'Anon 1'; }; ## This fails - $glob becomes a REF(0x....) # *{ *$glob } = sub{ print 'Anon'; }; # print "\n\nAfter \*{ *\$glob } = sub{ ... }: ", $glob; # >> After *{ *$glob } = sub{ ... }: REF(0x224fe4) ## This fails in the same way # *$glob = sub{ print 'Anon'; }; # print "\n\nAfter *\$glob = sub{ ... }: ", $glob; # >> After *$glob = sub{ ... }: REF(0x224fe4) ## And so does this. # *{ $glob } = sub{ print 'Anon'; }; # print "\n\nAfter \*{ \$glob } = sub{ ... }: ", $glob; # >> After *$glob = sub{ ... }: REF(0x224fe4) ## This (unsurprisingly) just assigns a normal coderef. # $glob = sub{ print 'Anon 2'; }; # print "\n\nAfter \$glob = sub{ ... }: ", $glob; # >> After $glob = sub{ ... }: CODE(0x18623a4) 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 ];


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
  • Comment on Assigning to the CODE slot of a GLOB whose REF is held in a lexical?
  • Download Code

Replies are listed 'Best First'.
Re: Assigning to the CODE slot of a GLOB whose REF is held in a lexical?
by ysth (Canon) on Nov 16, 2004 at 07:21 UTC
    $globref = \do{ local *GLOB} }; {local *X = $globref; *X = sub {"bar"}};
    should do the trick. I think it's a bug that *$globref = $coderef doesn't work. (Or $arrayref, $scalarref, $hashref, $formatref, $ioref, for that matter.)
Re: Assigning to the CODE slot of a GLOB whose REF is held in a lexical?
by revdiablo (Prior) on Nov 16, 2004 at 07:26 UTC

    Maybe I'm missing something, but this Works For Me:

    sub foo { "foo" } $fooref = \*foo; print *bar{SCALAR}; *bar = *$fooref{CODE}; print *bar{SCALAR}; print *foo{CODE}; print *bar{CODE};

    Update: I just noticed you want to assign to a globref. This works too:

    sub foo { "foo" } $fooref = \*foo; $bar = 1; $barref = \*bar; print *bar{SCALAR}; *$barref = *foo{CODE}; print *bar{SCALAR}; print *foo{CODE}; print *bar{CODE};

    Another Update: assigning an anonymous coderef to the glob ref doesn't overwrite the scalar slot of the glob for me either:

    $bar = 1; $barref = \*bar; print *bar{SCALAR}; *$barref = sub { "bar" }; print *bar{SCALAR};

      Doesn't for me:

      sub foo { "foo" } $fooref = \*foo; &$fooref();

      gives

      Not a CODE reference at testing.pl line 3.

      "Another Update" doesn't work for either:

      $bar = 1; $barref = \*bar; *$barref = sub { "bar" }; &$barref();

      gives

      Not a CODE reference at testing.pl line 4.

        That's because it's a glob reference, not a code reference:

        sub foo { "foo" } $fooref = \*foo; print *$fooref{CODE}->();
Re: Assigning to the CODE slot of a GLOB whose REF is held in a lexical?
by BrowserUk (Patriarch) on Nov 16, 2004 at 17:16 UTC

    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?


    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
      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.