maybe I overlooked something, but wouldn't specifying the full outer subname
(including its namespace) help?
like so:
.namespace ['B']
.sub 'inner' :outer(['A';'outer'])
...
.end
instead of the proposed :lexid property.
just a thought. maybe there's something i'm overlooking or missing, but to
me this seems like the most obvious solution.
kjs
On Tue, Jun 24, 2008 at 12:27 AM, Patrick R. Michaud <[EMAIL PROTECTED]>
wrote:
> There appears to be a fundamental design problem in Parrot's
> current implementation of :outer. The short summary is that
> :outer("sub_name") doesn't provide sufficient specificity
> to accurately resolve an outer sub.
>
> In particular, given:
>
> .namespace ['A']
> .sub 'outer'
> ...
> .end
>
> .namespace ['B']
> .sub 'outer'
> ...
> .lex '$a', x
> 'inner'()
> ...
> .end
>
> .sub 'inner' :outer('outer')
> $P0 = find_lex '$a'
> .end
>
> Parrot incorrectly uses A::outer as the :outer sub of B::inner.
> In fact, the :outer flag seems to always use the first sub
> that it finds having a matching name. At the bottom of this
> message I've added a fuller description and demonstration of
> the problem.
>
> Jonathan and I discussed this briefly on #parrot.
> Constraining :outer to subs only in the same namespace
> isn't a sufficient solution for at least two reasons:
>
> 1. Some languages (incl Perl 6) allow inner classes and inner
> namespaces that can access items in (outer) lexical scopes.
>
> 2. Some subs can be :multi -- i.e., multiple subs (each of which
> may be an independent outer scope) may be referenced by the
> same global symbol name.
>
> The best solution I've come up with thus far is to allow every sub to
> have a :lexid("...") attribute that uniquely identifies the sub.
> The :outer() flag would then refer to this lexid instead of the
> sub's name. A sub that doesn't supply a :lexid("...") attribute
> would use its normal name as its lexid (thus existing simple cases
> of :outer continue to work).
>
> An alternate approach would be go the other way -- have every sub
> use a unique name, and use an :export("xyz") flag to cause the
> sub to be placed in the namespace under its common name. The
> :anon flag would continue to mean "don't make an entry in the
> namespace", and omitting :export() would continue to use the sub's
> name as the exported name. (I choose :export here to parallel the
> proposal in RT#53302 regarding listing methods in namespaces,
> but any flag name would work for me.)
>
> Yet another approach would be to keep things as they are now,
> but have :outer only refer to the closest (most recent) version
> of a sub with that name. We still may have to be careful about
> dealing with :multi subs, though, and it might be possible to craft
> some HLL code where it's not possible to make this approach work.
>
> (A fourth approach, which I have a strong dislike for, is to have
> PCT always generate a unique name for every sub and then use a
> :load :init sub to bind them as their common names in the namespace.)
>
> Lexical symbol handling in Parrot is rapidly becoming a huge blocker
> for progress on Rakudo -- there are a number of cases in the test
> suite that have nested blocks and subs that can't really be implemented
> in Rakudo due to problems with Parrot's lexicals.
>
> Pm
>
> -----fuller description-----
>
> Here's a longish test program that demonstrates the problem.
> The key thing to note is that we have two subs named 'bar',
> albeit in different namespaces. The Foo::inner sub wants
> Foo::bar to be its :outer lexical scope.
>
> $ cat x.pir
> .sub 'main' :main
> 'bar'()
>
> $P0 = get_hll_global ['Foo'], 'bar'
> $P0('hello world')
> .end
>
> .sub 'printf'
> .param string fmt
> .param pmc args :slurpy
> $S0 = sprintf fmt, args
> print $S0
> .return ()
> .end
>
>
> .sub 'bar'
> $P0 = get_global 'bar'
> $I0 = get_addr $P0
> 'printf'("in global 'bar' (0x%x)\n", $I0)
> .end
>
>
> .namespace ['Foo']
> .sub 'bar'
> .param pmc x
> .lex '$a', x
>
> $P0 = get_global 'bar'
> $I0 = get_addr $P0
> 'printf'("in Foo::bar (0x%x)\n", $I0)
>
> 'inner'()
> 'printf'("back in Foo::bar (0x%x)\n", $I0)
> .end
>
>
> .sub 'inner' :outer('bar')
> $P0 = get_global 'inner'
> $I0 = get_addr $P0
> 'printf'("in Foo::inner (0x%x)\n", $I0)
>
> $P0 = getinterp
> $P1 = $P0['outer']
> $I1 = get_addr $P1
> 'printf'("Foo::inner's :outer is 0x%x\n", $I1)
>
> $P0 = find_lex '$a'
> say $P0
> .return ()
> .end
>
> When the above is run, we can see that Foo::inner incorrectly
> receives the global 'bar' sub as its outer scope. As a result,
> it's unable to find the lexical '$a' that was set by Foo::bar .
>
> $ ./parrot x.pir
> in global 'bar' (0x82484b8)
> in Foo::bar (0x8248508)
> in Foo::inner (0x82485b4)
> Foo::inner's :outer is 0x82484b8
> Lexical '$a' not found
> current instr.: 'parrot;Foo;inner' pc 136 (x.pir:48)
> called from Sub 'parrot;Foo;bar' pc 83 (x.pir:33)
> called from Sub 'main' pc 18 (x.pir:5)
>
> If we change the name of the global 'bar' to something like
> 'bar2', then Foo::inner correctly attaches Foo::bar as its outer
> sub and everything works fine:
>
> $ ./parrot y.pir
> in global 'bar2' (0x8248528)
> in Foo::bar (0x8248578)
> in Foo::inner (0x8248624)
> Foo::inner's :outer is 0x8248578
> hello world
> back in Foo::bar (0x8248578)
> $
>
>
>