Problem about type glob reference

Discussion in 'Perl Misc' started by Todd, Dec 25, 2007.

  1. Todd

    Todd Guest

    I meet with a inconsistent behavior about the type glob reference
    blow. Here Case3 works fine. But Case1 and Case2 file a compile error.
    The difference between Case2 and Case3 is that I move the typeglob
    assignment from inside SCOPE to outside SCOPE. I'm trying to
    understand this, may you help me?

    Case1:
    #! /bin/perl -l

    BEGIN {
    package Foo;
    sub foo { print "foo called"; }
    $main::{foo} = \&foo;
    }

    &main::foo();

    __END__
    Undefined subroutine &main::foo called at - line 9.


    Case2:
    #! /bin/perl -l

    BEGIN {
    package Foo;
    sub foo { print "foo called"; }
    $main::{foo} = \&Foo::foo;
    }

    &main::foo();

    __END__
    Undefined subroutine &main::foo called at - line 9.

    Case3:
    #! /bin/perl -l

    BEGIN {
    package Foo;
    sub foo { print "foo called"; }
    }

    $main::{foo} = \&Foo::foo;
    &main::foo();

    __END__

    foo called

    Thanks,
    Todd
     
    Todd, Dec 25, 2007
    #1
    1. Advertising

  2. Todd

    Todd Guest

    Todd wrote:
    > $main::{foo} = \&foo;

    I know the better one is
    *main::foo = \&foo;
    Or even better: use Exporter and use.

    But this doesn't explain my question. Hopefully some useful hints.

    Thanks,
    Todd
     
    Todd, Dec 25, 2007
    #2
    1. Advertising

  3. Todd

    Peter Scott Guest

    On Tue, 25 Dec 2007 05:40:29 -0800, Todd wrote:
    > #! /bin/perl -l
    >
    > BEGIN {
    > package Foo;
    > sub foo { print "foo called"; }
    > $main::{foo} = \&foo;
    > }
    >
    > &main::foo();
    >
    > __END__
    > Undefined subroutine &main::foo called at - line 9.


    I only have a few minutes to spare here before my battery runs out, but
    what's weird about this is (a) it works if you do something with foo()
    inside the BEGIN block, and (b) the result is different on 5.10.

    End the BEGIN block with, say,

    foo();
    or
    my $x = *main::foo{CODE};

    and it works. Try it on 5.10 and the error when calling &main::foo
    changes to "Cannot convert a reference to CODE to typeglob".

    --
    Peter Scott
    http://www.perlmedic.com/
    http://www.perldebugged.com/
     
    Peter Scott, Dec 25, 2007
    #3
  4. On Dec 25, 7:44 am, Peter Scott <> wrote:
    > On Tue, 25 Dec 2007 05:40:29 -0800, Todd wrote:
    > > #! /bin/perl -l

    >
    > > BEGIN {
    > > package Foo;
    > > sub foo { print "foo called"; }
    > > $main::{foo} = \&foo;
    > > }

    >
    > > &main::foo();

    >
    > > __END__
    > > Undefined subroutine &main::foo called at - line 9.

    >
    > I only have a few minutes to spare here before my battery runs out, but
    > what's weird about this is (a) it works if you do something with foo()
    > inside the BEGIN block, and (b) the result is different on 5.10.
    >
    > End the BEGIN block with, say,
    >
    > foo();


    In this case, Foo::foo() is called however:

    BEGIN { ...
    sub foo { print "foo called by ",(caller)[0];}
    foo();
    }

    foo called by Foo

    A package declaration has lexical scope and
    'main' is still undefined within BEGIN. This
    though would also work:


    BEGIN {
    package Foo;
    sub foo { print "foo called"; }
    $main::{foo} = \&foo;
    package main;
    foo()
    }

    > or
    > my $x = *main::foo{CODE};
    >
    > and it works. Try it on 5.10 and the error when calling &main::foo
    > changes to "Cannot convert a reference to CODE to typeglob".
    >


    No idea why the later works though..

    --
    Charles DeRykus
     
    comp.llang.perl.moderated, Dec 26, 2007
    #4
  5. Todd

    Todd Guest

    Peter Scott wrote:
    > End the BEGIN block with, say,
    >
    > foo();
    > or
    > my $x = *main::foo{CODE};
    >
    > and it works. Try it on 5.10 and the error when calling &main::foo


    So these 2 works below:

    #! /bin/perl -l
    BEGIN {
    package Foo;
    sub foo { print "foo called"; }
    $main::{foo} = \&Foo::foo;
    my $x = *main::foo{CODE};
    }

    &main::foo();

    __END__
    foo called


    #! /bin/perl -l
    {
    package Foo;
    sub foo { print "foo called"; }
    $main::{foo} = \&Foo::foo;
    }

    &main::foo();

    __END__

    foo called

    Seems it's related to the subtle meaning of BEGIN and reference count,
    can any one give a explanation about this?

    -Todd
     
    Todd, Dec 26, 2007
    #5
  6. On Dec 26, 6:23 am, Todd <> wrote:
    > Peter Scott wrote:
    > > End the BEGIN block with, say,

    >
    > > foo();
    > > or
    > > my $x = *main::foo{CODE};

    >
    > > and it works. Try it on 5.10 and the error when calling &main::foo

    >
    > So these 2 works below:
    >
    > #! /bin/perl -l
    > BEGIN {
    > package Foo;
    > sub foo { print "foo called"; }
    > $main::{foo} = \&Foo::foo;
    > my $x = *main::foo{CODE};
    > }
    >
    > &main::foo();
    >
    > __END__
    > foo called
    >
    > #! /bin/perl -l
    > {
    > package Foo;
    > sub foo { print "foo called"; }
    > $main::{foo} = \&Foo::foo;
    > }
    >
    > &main::foo();
    >
    > __END__
    >
    > foo called
    >
    > Seems it's related to the subtle meaning of BEGIN and reference count,
    > can any one give a explanation about this?


    You might be right but somehow I think there's
    more to it.. including lexical package scope.
    Just a simple declaration of 'main' inside
    BEGIN {} works:

    #! /bin/perl -l

    BEGIN {
    package main;
    sub foo { print "foo called..."; }
    }

    foo();
    __END__
    foo called...

    Note 'foo' also becomes available via 'use subs' occurring at compile
    time too:

    use subs 'foo';
    BEGIN {
    package Foo;
    sub foo { print "foo called...'; }
    $main::{foo} = \&Foo::foo;
    # my $x = *main::foo{CODE};
    }
    foo();
    __END__
    foo called...

    --
    Charles DeRykus
     
    comp.llang.perl.moderated, Dec 26, 2007
    #6
  7. On Dec 25, 5:40 am, Todd <> wrote:
    > I meet with a inconsistent behavior about the type glob reference
    > blow. Here Case3 works fine. But Case1 and Case2 file a compile error.
    > The difference between Case2 and Case3 is that I move the typeglob
    > assignment from inside SCOPE to outside SCOPE. I'm trying to
    > understand this, may you help me?
    >
    > Case1:
    > #! /bin/perl -l
    >
    > BEGIN {
    > package Foo;
    > sub foo { print "foo called"; }
    > $main::{foo} = \&foo;
    > }
    >
    > &main::foo();
    >
    > __END__
    > Undefined subroutine &main::foo called at - line 9.
    >
    > Case2:
    > #! /bin/perl -l
    >
    > BEGIN {
    > package Foo;
    > sub foo { print "foo called"; }
    > $main::{foo} = \&Foo::foo;
    > }
    >
    > &main::foo();
    >
    > __END__
    > Undefined subroutine &main::foo called at - line 9.
    >
    > Case3:
    > #! /bin/perl -l
    >
    > BEGIN {
    > package Foo;
    > sub foo { print "foo called"; }
    > }
    >
    > $main::{foo} = \&Foo::foo;
    > &main::foo();
    >
    > __END__
    >
    > foo called
    >


    Reducing all these to a simple example:

    BEGIN {
    sub Foo::foo { print "foo called..."; }
    $main::{foo} = \&Foo::foo; # assign ref.
    }

    foo(); # fails with "undef. subroutine ...


    However, as noted earlier, moving the 'assign ref.' line above outside
    BEGIN {} just before the foo() call works. Adding 'use vars "foo"' at
    the top works too. Suprisingly so does adding '$::foo = 1' inside --
    but not outside -- BEGIN {} does too.

    With these diverse solutions, I suspect Perl has some heuristic about
    whether to discard the glob assignment but I really doubt it's just a
    ref. count.

    --
    Charles DeRykus
     
    comp.llang.perl.moderated, Dec 28, 2007
    #7
  8. Todd

    Peter Scott Guest

    On Fri, 28 Dec 2007 05:26:13 -0800, comp.llang.perl.moderated wrote:
    > Reducing all these to a simple example:
    >
    > BEGIN {
    > sub Foo::foo { print "foo called..."; }
    > $main::{foo} = \&Foo::foo; # assign ref.
    > }
    >
    > foo(); # fails with "undef. subroutine ...
    >
    >
    > However, as noted earlier, moving the 'assign ref.' line above outside
    > BEGIN {} just before the foo() call works. Adding 'use vars "foo"' at
    > the top works too. Suprisingly so does adding '$::foo = 1' inside --
    > but not outside -- BEGIN {} does too.
    >
    > With these diverse solutions, I suspect Perl has some heuristic about
    > whether to discard the glob assignment but I really doubt it's just a
    > ref. count.


    It is not exactly discarding the glob assignment. Try it on 5.10 and see
    what error you get.

    As a p5p poster pointed out, the assignment should be:

    *main::foo = \&foo;

    and all is right with the world. That doesn't explain what is going on
    with this code, but it does solve the OP's problem.

    --
    Peter Scott
    http://www.perlmedic.com/
    http://www.perldebugged.com/
     
    Peter Scott, Dec 28, 2007
    #8
  9. On Dec 28, 6:15 am, Peter Scott <> wrote:
    > On Fri, 28 Dec 2007 05:26:13 -0800, comp.llang.perl.moderated wrote:
    > > Reducing all these to a simple example:

    >
    > > BEGIN {
    > > sub Foo::foo { print "foo called..."; }
    > > $main::{foo} = \&Foo::foo; # assign ref.
    > > }

    >
    > > foo(); # fails with "undef. subroutine ...

    >
    > > However, as noted earlier, moving the 'assign ref.' line above outside
    > > BEGIN {} just before the foo() call works. Adding 'use vars "foo"' at
    > > the top works too. Suprisingly so does adding '$::foo = 1' inside --
    > > but not outside -- BEGIN {} does too.

    >
    > > With these diverse solutions, I suspect Perl has some heuristic about
    > > whether to discard the glob assignment but I really doubt it's just a
    > > ref. count.

    >
    > It is not exactly discarding the glob assignment. Try it on 5.10 and see
    > what error you get.
    >
    > As a p5p poster pointed out, the assignment should be:
    >
    > *main::foo = \&foo;



    Interesting, that does the trick as well. I'm
    confused why the alternate *main{foo} doesn't
    work as well though. *main::foo is accessed
    more efficiently at compile time but $main::{foo}
    won't create a new typeglob if none previously
    exists. So, I'm not sure why the former should
    viewed preferentially...

    >
    > and all is right with the world. That doesn't explain what is going on
    > with this code, but it does solve the OP's problem.


    It also doesn't explain why 'use vars "foo"'
    or '$::foo = 1' in the BEGIN causes all to be
    "right with the world" :)

    Thanks for the info.
    --
    Charles DeRykus
     
    comp.llang.perl.moderated, Dec 29, 2007
    #9
  10. Todd

    Ben Morrow Guest

    Quoth "comp.llang.perl.moderated" <>:
    > On Dec 28, 6:15 am, Peter Scott <> wrote:
    > > On Fri, 28 Dec 2007 05:26:13 -0800, comp.llang.perl.moderated wrote:
    > > > Reducing all these to a simple example:

    > >
    > > > BEGIN {
    > > > sub Foo::foo { print "foo called..."; }
    > > > $main::{foo} = \&Foo::foo; # assign ref.
    > > > }

    > >
    > > > foo(); # fails with "undef. subroutine ...

    > >

    <snip: $main::{foo} outside BEGIN works>
    > >
    > > > With these diverse solutions, I suspect Perl has some heuristic about
    > > > whether to discard the glob assignment but I really doubt it's just a
    > > > ref. count.

    > >
    > > It is not exactly discarding the glob assignment. Try it on 5.10 and see
    > > what error you get.
    > >
    > > As a p5p poster pointed out, the assignment should be:
    > >
    > > *main::foo = \&foo;

    >
    > Interesting, that does the trick as well.


    That's unsurprising: it's the supported and documented way of doing
    this.

    > I'm confused why the alternate *main{foo} doesn't work as well
    > though.


    Huh? I think you need to read perlref again. Typeglobs don't have a foo
    slot, and even if they did it would have nothing to do with any sub
    named &foo in any package.

    > *main::foo is accessed more efficiently at compile time but
    > $main::{foo} won't create a new typeglob if none previously exists.


    ....which is the root of the problem. %main:: is 'just' an ordinary hash:
    it doesn't know it's a symbol table, and it doesn't know it should only
    contain globs. So

    $main::{foo} = \&Foo::foo;

    puts a subref directly in the symbol table, where a glob should be.
    Unsurprisingly, this doesn't work: when perl later tries to look up
    &main::foo, it can't find a typeglob for it. 5.10 gives a slightly more
    helpful message than 5.8, probably because 5.10 *does* sometimes expect
    to find things other than typeglobs in the symbol table. For instance:

    ~% perl5.8.8 -le'BEGIN{ $main::{foo} = \2 } print foo'
    Undefined subroutine &main::foo called at -e line 1.
    ~% perl5.10.0 -le'BEGIN{ $main::{foo} = \2 } print foo'
    2
    ~%

    > > and all is right with the world. That doesn't explain what is going on
    > > with this code, but it does solve the OP's problem.

    >
    > It also doesn't explain why 'use vars "foo"'
    > or '$::foo = 1' in the BEGIN causes all to be
    > "right with the world" :)


    *Any* reference to *main::foo before perl reaches the assignment causes
    $main::{foo} to be filled with a typeglob automatically. So even
    removing the BEGIN fixes the problem, as when perl compiles the call to
    &main::foo it creates the typeglob, so by the time it gets to the
    assignment (at runtime) there is already a glob there. At that point
    normal glob assignment magic kicks in.

    Ben
     
    Ben Morrow, Dec 29, 2007
    #10
  11. On Dec 29, 6:48 am, Ben Morrow <> wrote:
    > Quoth "comp.llang.perl.moderated" <>:> On Dec 28, 6:15 am, Peter Scott <> wrote:
    > > > On Fri, 28 Dec 2007 05:26:13 -0800, comp.llang.perl.moderated wrote:
    > > > > Reducing all these to a simple example:

    >
    > > > > BEGIN {
    > > > > sub Foo::foo { print "foo called..."; }
    > > > > $main::{foo} = \&Foo::foo; # assign ref.
    > > > > }

    >
    > > > > foo(); # fails with "undef. subroutine ...

    >
    > <snip: $main::{foo} outside BEGIN works>
    >
    >
    >
    > > > > With these diverse solutions, I suspect Perl has some heuristic about
    > > > > whether to discard the glob assignment but I really doubt it's just a
    > > > > ref. count.

    >
    > > > It is not exactly discarding the glob assignment. Try it on 5.10 and see
    > > > what error you get.

    >
    > > > As a p5p poster pointed out, the assignment should be:

    >
    > > > *main::foo = \&foo;

    >
    > > Interesting, that does the trick as well.

    >
    > That's unsurprising: it's the supported and documented way of doing
    > this.
    >
    > > I'm confused why the alternate *main{foo} doesn't work as well
    > > though.

    >
    > Huh? I think you need to read perlref again. Typeglobs don't have a foo
    > slot, and even if they did it would have nothing to do with any sub
    > named &foo in any package.


    Typo... I meant $main{foo} of course...
    >
    > > *main::foo is accessed more efficiently at compile time but
    > > $main::{foo} won't create a new typeglob if none previously exists.

    >
    > ...which is the root of the problem. %main:: is 'just' an ordinary hash:
    > it doesn't know it's a symbol table, and it doesn't know it should only
    > contain globs. So
    >
    > $main::{foo} = \&Foo::foo;
    >
    > puts a subref directly in the symbol table, where a glob should be.
    > Unsurprisingly, this doesn't work: when perl later tries to look up
    > &main::foo, it can't find a typeglob for it. 5.10 gives a slightly more
    > helpful message than 5.8, probably because 5.10 *does* sometimes expect
    > to find things other than typeglobs in the symbol table. For instance:
    >
    > ~% perl5.8.8 -le'BEGIN{ $main::{foo} = \2 } print foo'
    > Undefined subroutine &main::foo called at -e line 1.
    > ~% perl5.10.0 -le'BEGIN{ $main::{foo} = \2 } print foo'
    > 2
    > ~%
    >
    > > > and all is right with the world. That doesn't explain what is going on
    > > > with this code, but it does solve the OP's problem.

    >
    > > It also doesn't explain why 'use vars "foo"'
    > > or '$::foo = 1' in the BEGIN causes all to be
    > > "right with the world" :)

    >
    > *Any* reference to *main::foo before perl reaches the assignment causes
    > $main::{foo} to be filled with a typeglob automatically. So even
    > removing the BEGIN fixes the problem, as when perl compiles the call to
    > &main::foo it creates the typeglob, so by the time it gets to the
    > assignment (at runtime) there is already a glob there. At that point
    > normal glob assignment magic kicks in.
    >


    Great explanation. I'll re-read perlref.

    --
    Charles DeRykus
     
    comp.llang.perl.moderated, Dec 29, 2007
    #11
  12. Todd

    Ben Morrow Guest

    Quoth "comp.llang.perl.moderated" <>:
    > On Dec 29, 6:48 am, Ben Morrow <> wrote:
    > > Quoth "comp.llang.perl.moderated" <>:> On

    > Dec 28, 6:15 am, Peter Scott <> wrote:
    > >
    > > > > As a p5p poster pointed out, the assignment should be:

    > >
    > > > > *main::foo = \&foo;

    > >
    > > > Interesting, that does the trick as well.

    > >
    > > That's unsurprising: it's the supported and documented way of doing
    > > this.
    > >
    > > > I'm confused why the alternate *main{foo} doesn't work as well
    > > > though.

    > >
    > > Huh? I think you need to read perlref again. Typeglobs don't have a foo
    > > slot, and even if they did it would have nothing to do with any sub
    > > named &foo in any package.

    >
    > Typo... I meant $main{foo} of course...


    No, you didn't... :)

    $main{foo} is an element of %main, aka %main::main, a perfectly ordinary
    hash. $main::{foo} is an element of %main::, which is the symbol table
    for the 'main' package, and (should) contain raw globs rather than
    ordinary scalars.

    > Great explanation. I'll re-read perlref.


    What documentation there is of this is in perlmod, under 'Symbol
    Tables', but it's not terribly clear. The only correct reference for
    things like this is the source, of course :).

    Ben
     
    Ben Morrow, Dec 29, 2007
    #12
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Georgy Pruss
    Replies:
    15
    Views:
    751
    Tim Roberts
    Dec 1, 2003
  2. Tim Peters
    Replies:
    1
    Views:
    378
    Duncan Booth
    Dec 1, 2003
  3. Sean Berry

    Question about glob.glob <--newbie

    Sean Berry, May 4, 2004, in forum: Python
    Replies:
    3
    Views:
    356
    David M. Cooke
    May 4, 2004
  4. Elbert Lev

    glob.glob unicode bug or feature

    Elbert Lev, Jul 31, 2004, in forum: Python
    Replies:
    5
    Views:
    412
    Neil Hodgson
    Aug 2, 2004
  5. lameck kassana
    Replies:
    0
    Views:
    300
    lameck kassana
    Feb 26, 2009
Loading...

Share This Page