Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

:anon Subs and Namespaces

17 views
Skip to first unread message

Matt Diephouse

unread,
Nov 22, 2006, 4:02:49 AM11/22/06
to Allison Randal, parrot-...@perl.org
Let's try this again, starting from the Tcl side of things. Tcl code
can exist outside of subroutines. This, for example, is a valid Tcl
program:

set number 5
puts $number

In order to compile this to PIR, we have to put it into a subroutine.
The only problem with putting it into a subroutine is that we don't
want to pollute our namespace. So, naturally, we make it an :anon sub.
Here is an extremely simplified version (that represents the ideal,
but probably unattainable, emitted PIR):

.HLL 'tcl', 'tcl_group'
.namespace

.sub 'main' :anon :main
.local pmc number
number = new .TclInt
number = 5
set_global 'number', number
say number
.end

That doesn't look too bad. This actually works and correctly stores
the "number" variable in the root HLL namespace. But things get a
little hairier when we start using namespaces in Tcl:

namespace eval test {
set number 5
puts $number
}

This is the equivalent of running the first example in a different
namespace. So, again, the simplified, ideal PIR is:

.HLL 'tcl', 'tcl_group'
.namespace ['test']

.sub 'main' :anon :main
.local pmc number
number = new .TclInt
number = 5
set_global 'number', number
say number
.end

But here we run across the behavior that led me to file RT#40955: I
have an anon namespace that uses the notion of the current namespace.
The code is the same, but the PIR example doesn't work because the
"current namespace" inside the :anon sub is the root HLL namespace. So
while

set_global 'number', number

would normally be equivalent to

set_hll_global ['test'], 'number', number

in this case, it's actually equivalent to

set_hll_global 'number', number.

All this because when Parrot sees an :anon sub it attaches the root
HLL namespace to it (or did, before I applied my "fix"). It's not that
it doesn't attach any namespace to it, it's that always attaches the
root HLL namespace regardless of the namespace it's declared in.

That, at least, ought to change. If there is no notion of a current
namespace in an :anon sub outside of a closure, then trying to use one
ought to make things blow up so I can see the error in my ways. :-)

Still, I'm curious to see what reasons there are for not attaching a
namespace to an :anon sub when (1) it seems convenient and (2) all of
Parrot's tests still pass. Does this break anything? Or did this just
signal to you that there may a problem here that needs its own
solution?

--
Matt Diephouse
http://matt.diephouse.com

Allison Randal

unread,
Nov 22, 2006, 11:36:53 PM11/22/06
to ma...@diephouse.com, parrot-...@perl.org
Matt Diephouse wrote:
> Let's try this again, starting from the Tcl side of things. Tcl code
> can exist outside of subroutines. This, for example, is a valid Tcl
> program:
>
> set number 5
> puts $number

[...]

> But things get a
> little hairier when we start using namespaces in Tcl:
>
> namespace eval test {
> set number 5
> puts $number
> }
>
> This is the equivalent of running the first example in a different
> namespace. So, again, the simplified, ideal PIR is:
>
> .HLL 'tcl', 'tcl_group'
> .namespace ['test']
>
> .sub 'main' :anon :main
> .local pmc number
> number = new .TclInt
> number = 5
> set_global 'number', number
> say number
> .end

Okay, so we're basically solving the same problem as Perl 5's "main"
routine, which it stuffs in an obscure C variable internal to the
interpreter, not accessible from the symbol table. (Talk about
less-than-transparent introspection.)

I don't fully grok Tcl, so a few questions (which may or may not be
relevant): Where do mainstream implementations of Tcl store that
executable "main" block of code? Or, more importantly, where do they
store 'number' in the case without the namespace and the case with the
namespace?

> But here we run across the behavior that led me to file RT#40955: I
> have an anon namespace that uses the notion of the current namespace.
> The code is the same, but the PIR example doesn't work because the
> "current namespace" inside the :anon sub is the root HLL namespace. So
> while
>
> set_global 'number', number
>
> would normally be equivalent to
>
> set_hll_global ['test'], 'number', number
>
> in this case, it's actually equivalent to
>
> set_hll_global 'number', number.
>
> All this because when Parrot sees an :anon sub it attaches the root
> HLL namespace to it (or did, before I applied my "fix"). It's not that
> it doesn't attach any namespace to it, it's that always attaches the
> root HLL namespace regardless of the namespace it's declared in.
>
> That, at least, ought to change.

Agreed, that is b0rken. (Namespaces are new enough that Parrot still has
a bad habit of defaulting to root namespaces.) And, agreed that
set_global and related opcodes need some namespace to default to.

> Still, I'm curious to see what reasons there are for not attaching a
> namespace to an :anon sub when (1) it seems convenient and (2) all of
> Parrot's tests still pass. Does this break anything? Or did this just
> signal to you that there may a problem here that needs its own
> solution?

Yes and yes. One common use of anonymous subs in a dynamic language is
for later exporting them into another package (or multiple different
packages). In that case, you really don't want the sub to retain a link
to its defining namespace, you want it to fully adopt the namespace it's
pushed into. Which has everything to do with the earlier Perl example of
creating anonymous subroutines, but little to do with creating "main"
routines, since they don't change packages. (Code examples are helpful.)

Let's see... for :main, :load, :method, and :vtable compilation units it
makes sense to default lookups to the namespace where they were defined,
even if they're anonymous. For an ordinary :anon .sub (with no :vtable,
:method, :load, :main, etc) I could argue it either way, but with the
other uses remaining tied to the namespace where they were defined,
let's default to your fix (consistency is good).

Then for exporting (and other dynamic tricks), let's look into a feature
that allows you to change the namespace a compilation unit uses for
default lookups, after it's compiled.

Allison

Matt Diephouse

unread,
Nov 23, 2006, 12:13:50 PM11/23/06
to Allison Randal, parrot-...@perl.org
Allison Randal <all...@perl.org> wrote:
> Okay, so we're basically solving the same problem as Perl 5's "main"
> routine, which it stuffs in an obscure C variable internal to the
> interpreter, not accessible from the symbol table. (Talk about
> less-than-transparent introspection.)

Huh. I don't know anything about Perl 5's internals, but that's
interesting and it makes a lot of sense.

> I don't fully grok Tcl, so a few questions (which may or may not be
> relevant): Where do mainstream implementations of Tcl store that
> executable "main" block of code? Or, more importantly, where do they
> store 'number' in the case without the namespace and the case with the
> namespace?

The official Tcl implementation is an interpreter, not a compiler. So
I suspect the answer to your question is "it doesn't". But without a
namespace, 'number' is stored in the root HLL namespace; it could also
be accessed absolutely (C< $::number >).

> One common use of anonymous subs in a dynamic language is
> for later exporting them into another package (or multiple different
> packages). In that case, you really don't want the sub to retain a link
> to its defining namespace, you want it to fully adopt the namespace it's
> pushed into. Which has everything to do with the earlier Perl example of
> creating anonymous subroutines, but little to do with creating "main"
> routines, since they don't change packages. (Code examples are helpful.)

I'm struggling to understand what you're saying here. You noted before
that Perl 5's anonymous subroutines are full dynamic closures. As
such, they don't ever fully adopt the namespace they're pushed into.
Are you thinking of a different language? or am I missing a case?

> Let's see... for :main, :load, :method, and :vtable compilation units it
> makes sense to default lookups to the namespace where they were defined,
> even if they're anonymous. For an ordinary :anon .sub (with no :vtable,
> :method, :load, :main, etc) I could argue it either way, but with the
> other uses remaining tied to the namespace where they were defined,
> let's default to your fix (consistency is good).

I was hoping you'd say that. :-)

> Then for exporting (and other dynamic tricks), let's look into a feature
> that allows you to change the namespace a compilation unit uses for
> default lookups, after it's compiled.

That seems like a good idea.

Bob Rogers

unread,
Nov 23, 2006, 12:40:54 PM11/23/06
to Allison Randal, ma...@diephouse.com, Ben Morrow, parrot-...@perl.org
From: Allison Randal <all...@perl.org>
Date: Wed, 22 Nov 2006 20:37:26 -0800

Ben Morrow wrote:
>
> ...but that's just a braino on Matt's part, and his point still stands
> for the code
>
> package Test;
>
> sub apply {
> my $func = shift;
> $func->(shift) while @_;
> }
>
> package Foo;
> use vars qw/$line/; # can't use our as that also creates a lexical :(
>
> $line = 0;
> my $func = sub {
> print $line++, ' ', shift(), "\n";
> };
>
> Test::apply($func, qw(a b c d));
>
> In this case $func picks up $Foo::line rather than $Test::line or
> $::line, even though it's anonymous.

It's still a closure. Perl 5 just isn't a good example here, since all
anonymous subs are closures.

Allison

It is not closing over $Foo::line, though, which is a free reference to
a global, and not a lexical. (It doesn't need to be a closure at all,
because AFAICS there are no lexicals in scope.)

But this just seems to show that the namespace name really belongs to
the global, not to the sub. In other words, this should compile to code
that uses

line = get_global ['Foo'], '$line'

rather than

line = get_global '$line'

and similarly for set_global.

So the real question is this: Do we even need the two-arg forms of
get_global and set_global, or are these just sources of confusion?
After all, the namespace argument could always be filled in by IMCC,
since it's fixed at compile time.

From: Allison Randal <all...@perl.org>
Date: Wed, 22 Nov 2006 20:36:53 -0800

. . .

. . . One common use of anonymous subs in a dynamic language is

for later exporting them into another package (or multiple different
packages). In that case, you really don't want the sub to retain a link
to its defining namespace, you want it to fully adopt the namespace it's
pushed into. Which has everything to do with the earlier Perl example of
creating anonymous subroutines, but little to do with creating "main"
routines, since they don't change packages. (Code examples are helpful.)

Let's see... for :main, :load, :method, and :vtable compilation units it
makes sense to default lookups to the namespace where they were defined,
even if they're anonymous. For an ordinary :anon .sub (with no :vtable,
:method, :load, :main, etc) I could argue it either way, but with the
other uses remaining tied to the namespace where they were defined,
let's default to your fix (consistency is good).

Then for exporting (and other dynamic tricks), let's look into a feature
that allows you to change the namespace a compilation unit uses for
default lookups, after it's compiled.

Allison

"Full adoption" seems problematic to me. What if the end of this code
(as revised by Ben) is changed to this:

# new magic.
*Baz::other_func = $func;

# . . . and some time later:
Test::apply(\&Baz::other_func, qw(a b c d));

Are you saying that \&Baz::other_func should access the (undeclared)
$Baz::line variable, instead of $Foo::line ? And what about this:

# multiple magic.
*Baz::other_func = $func;
*Quux::still_another_func = $func;

Should &Baz::other_func and &Quux::still_another_func reference the same
or different globals? IMHO, if the programmer intended the answer to be
"different globals" at runtime, s/he could have written this with
explicit glob manipulation. Or, better still, used a closure.

-- Bob

Allison Randal

unread,
Dec 6, 2006, 11:56:19 PM12/6/06
to ma...@diephouse.com, parrot-...@perl.org
Matt Diephouse wrote:
>
>> One common use of anonymous subs in a dynamic language is
>> for later exporting them into another package (or multiple different
>> packages). In that case, you really don't want the sub to retain a link
>> to its defining namespace, you want it to fully adopt the namespace it's
>> pushed into. [...]

>
> I'm struggling to understand what you're saying here. You noted before
> that Perl 5's anonymous subroutines are full dynamic closures. As
> such, they don't ever fully adopt the namespace they're pushed into.
> Are you thinking of a different language? or am I missing a case?

Indeed that's true. And it's why SUPER is broken for exported methods in
Perl 5. An exported method calls a SUPER method on the parent of the
class where it was defined, instead of calling a SUPER method on the
parent of the class where it was exported to. Giving you weird effects
like:

Foo::Child inherits from Foo, but Bar::Child inherits from Bar. When you
call a method on Bar::Child that was exported from Foo::Child, it calls
Foo's method as the SUPER of Bar::Child when it should call Bar's method.

------
Calling from Foo object:
Foo implementation
------
Calling from Foo::Child object:
Foo::Child implementation (object is a Foo::Child)
SUPER is: Foo implementation
------
Calling from Bar object:
Bar implementation
------
Calling from Bar::Child object:
Foo::Child implementation (object is a Bar::Child)
SUPER is: Foo implementation
------

If Perl 6 doesn't fix this problem, other languages will, so Parrot
should support a sane implementation. (And still also support Perl 5's
odd way.)

Allison

0 new messages