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

Reply via email to