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) > $ > > >