Problem about type glob reference
Problem about type glob reference
am 25.12.2007 14:40:29 von xueweizhong
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
Re: Problem about type glob reference
am 25.12.2007 14:45:10 von xueweizhong
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
Re: Problem about type glob reference
am 25.12.2007 16:44:09 von Peter Scott
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/
Re: Problem about type glob reference
am 26.12.2007 07:49:32 von Charles DeRykus
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
Re: Problem about type glob reference
am 26.12.2007 15:23:40 von xueweizhong
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
Re: Problem about type glob reference
am 26.12.2007 19:16:31 von Charles DeRykus
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
Re: Problem about type glob reference
am 28.12.2007 14:26:13 von Charles DeRykus
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
Re: Problem about type glob reference
am 28.12.2007 15:15:37 von Peter Scott
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/
Re: Problem about type glob reference
am 29.12.2007 05:50:47 von Charles DeRykus
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
Re: Problem about type glob reference
am 29.12.2007 15:48:07 von Ben Morrow
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 ...
> >
> >
> > > 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
Re: Problem about type glob reference
am 29.12.2007 20:33:37 von Charles DeRykus
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 ...
>
>
>
>
>
> > > > 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
Re: Problem about type glob reference
am 29.12.2007 21:04:19 von Ben Morrow
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