From: "Patrick R. Michaud" <[EMAIL PROTECTED]>
   Date: Wed, 9 Jul 2008 18:49:53 -0500

   On Wed, Jul 09, 2008 at 04:46:19PM -0400, Bob Rogers wrote:
   > Not true.  The compiler always knows when it's compiling a closure.  So
   > if, at the point of definition, the emitted code does:
   >    foo_closure = newclosure foo_sub
   >    set_hll_global 'foo', foo_closure
   > then the compiler doesn't have to treat calls to "foo" specially.

   So, if I understand you correctly, for something like

       for 1..10 -> $x {
           sub foo() { say $x; }
           foo();
       }

   you're saying we should replace the 'foo' symbol ten times -- each
   time with a newclosure taken from whatever was previously stored
   there.

Yes; because I think that is what the code means.  Indeed, I think you
yourself have already suggest that making closures in a loop requires
newclosure anyway [0].  Or are you saying that this case is different?
Shouldn't

       for 1..10 -> $x {
           sub foo() { say $x; }
           push(@foos, \&foo);
       }

produce the same result as

       for 1..10 -> $x {
           my $foo = sub { say $x; };
           push(@foos, $foo);
       }

modulo global namespace mangling (and broken Perl 6 syntax)?  And if
not, why not?

   Also, we can't do this exactly at the point of definition, because
   sub calls can lexically occur before the definition of the thing
   they're calling.  So it has to be moved higher in the block somehow.

Eh?  Can't do what at the point of definition?  Do you have an example?

   >    It all gets worse if I have something like:
   >        .sub 'abc' :multi('Integer')
   >       ...
   >        .end
   >        .sub 'abc' :multi('String') :outer('xyz')
   >       ...
   >        .end
   >    One of these is a Sub PMC, the other is a Closure PMC, and the thing
   >    that is stored under symbol 'abc' is neither -- that's a MultiSub PMC.  
   >    I'm fairly certain I can't do "newclosure" on the MultiSub PMC . . . 
   > 
   > I think you're right, but that is probably for good reason; I don't
   > think it makes sense.  Instead, you should do newclosure on the method
   > sub, and then define the closure as a method on the MultiSub.  And if
   > you can't do that, I claim that is a shortcoming of the Parrot MOP.

   I don't know what you're meaning by "method sub" here, but I'm not 
   sure it's important that I know . . .

I just mean "the sub that implements the body of the method."  I would
define it as a normal sub, create a closure with newclosure, and do
"add_method" (or equivalent) to tell the multi to dispatch to the
closure on the appropriate classes.  I alluded to the need for such a
PIR API last December [1] in order to support anonymous classes, but
this API is needed for closure methods as well.

   So, if the "correct" answer is that a sub definition should
   rebind the sub's name to the result of a newclosure opcode, my
   response is "okay, but that doesn't seem to work for MultiSubs".  
   If the response to that is "Parrot's MultiSub model is broken", I won't
   argue with that, but then someone (probably shouldn't be me, but 
   I'll do it if there's no other option) needs to design and 
   implement a model that isn't broken, or suggest how languages 
   can work around it.

I have been itching to experiment along these lines in Kea-CL for more
than a year now, but I've been too busy nailing down prerequisites (like
having a working native compiler) even to get started.  Sigh.

   In any case, IIUC, the current model doesn't support everything that
will be needed for Perl 6, so something will have to be changed.  I
suspect it will look like the "add_method" API to which I alluded above.
But I would rather be closer to having a practical compiler
implementation before I try to propose anything.

   . . .

   I don't disagree that it's possible for a compiler to always know the
   context and emit code that knows the correct context.  But in some
   sense that's what the compiler is already doing when it provides an
   :outer() flag to Parrot -- it's telling Parrot what the right context
   is.

:outer tells Parrot what the *static* relationships are.  "newclosure"
tells Parrot the proper dynamic relationship.  You may be correct that
the static relationship sometimes implies enough about the dynamic one
to get the right answer, but I am not convinced.  I will continue to
ignore "autoclose" -- except, of course, when it blows up in my face.

   (By way of analogy, I think that one can equally argue that Parrot
   should not need to support :method flags or automatically install
   subs as methods by default, because a compiler will know that
   something is a method and can emit code to install the sub as one.)

:method flags are declaring purely static information, so the analogy
doesn't fly.

   . . .

   >    Along those lines, it occurs to me that badlex.pir doesn't solve the
   > general case for the Perl 6 example you posted.  What should happen if I
   > add "inner()" in main before the first "foo" call?  

   I haven't been thinking about that case yet.   I suspect
   it will be some sort of runtime error, or that it will use an
   empty (and incorrect) lexical from "somewhere".  But the 
   "replace the symbol at the point of declaration" approach 
   described above really doesn't handle this case either.

Doesn't it?  Seems to me that it gives you the "undefined sub" runtime
error.

   > Fine by me.  And, since it sounds like you think that recursive-lex.pir
   > also ought to work (and assuming no one else objects), I will add it as
   > a "todo" case, so we can be sure that *that* also continues to work.

   None of my tickets have meant to imply that a particular PIR
   snippet "ought to work" . . .

   So, I'm not really taking a position either for or against 
   recursive-lex.pir, other than to say that whatever HLL feature
   it's intended to support ought to be supported somehow.

   Pm

That's really all I meant:  That you weren't taking a position against
it.

   ================
   From: "Patrick R. Michaud" <[EMAIL PROTECTED]>
   Date: Wed, 9 Jul 2008 19:30:19 -0500

   On Wed, Jul 09, 2008 at 03:45:31PM -0700, chromatic wrote:

   > That example is fine with me.  I almost deleted all of the hijinks
   > necessary in Closure PMC to attach to a never-initialized outer
   > lexical scope before I read the lexical spec again and realized
   > that someone designed it that way.  ...  Given the simplicity of
   > the workaround (which actually works) and the difficulty of making
   > the broken-as-designed feature work partially, I vote for removing
   > the brokenness.

   FWIW, I don't have any problem with having Parrot throw an exception 
   if someone invokes an inner lexical scope for which its outer lexical 
   scope has not been invoked yet.  Let's solve that problem when we come
   to it (and I don't know that Perl 6 will ever come to it -- again,
   I haven't worried about that case yet).

   Pm

Great; I don't want to worry about this case, either.  But that doesn't
address chromatic's point . . .

   ================
   From: "Patrick R. Michaud" <[EMAIL PROTECTED]>
   Date: Wed, 9 Jul 2008 19:37:40 -0500

   ...would we also have to generate code to restore the previous
   value of 'foo' upon exiting the sub?  (Think recursive calls here.)

       sub bar($x) {
           sub foo() { say $x; }
           if ($x > 0) { bar($x-1); }
           foo();
       }

   Pm

No.  AFAIK, "sub foo() { ... }" always mangles the global definition of
foo.  So in Perl 5, the first call wins; in Perl 6, it might be the last
call, but I don't really know.  And saying

           my sub foo() { say $x; }

doesn't define a global foo, so is not a problem; it ought to translate
to exactly the same code as the "my $foo = sub ..." example.

   Now if you had said "local sub foo ...", that would have been a
different can of worms . . .

   To summarize, I am not arguing that relying on "autoclose" is
necessarily wrong, and that we should therefore get rid of it.  For my
purposes, I am happy just to ignore it.  However, it seems to me that
using "newclosure" is safer, and that compilers should choose to
autoclose a given sub only as an optimization, and only after carefully
verifying that the closure cannot be called in a way that gives
incorrect results.

   But, having said that, it occurs to me that allowing the closure to
be globally accessible, as done by the "sub foo ..." examples, *ensures*
that the compiler cannot guarantee this.  So I guess I *am* arguing that
autoclose is necessarily wrong, at least for subs not marked :anon.
But, again, I don't expect it to go away.

                                        -- Bob

[0]  FWIW, the last example is reminiscent of make_closures_loop in the
     "Lexical scopes are too coarse-grained for loops" thread.
     http://www.nntp.perl.org/group/perl.perl6.internals/2007/08/msg39455.html
     RT#44395 [has Patrick's sample PIR]

[1]  http://www.nntp.perl.org/group/perl.perl6.internals/2007/12/msg42231.html

Reply via email to