On Wed, Jul 09, 2008 at 04:46:19PM -0400, Bob Rogers wrote: > From: "Patrick R. Michaud" <[EMAIL PROTECTED]> > ... > If we now say that a newclosure op is required to invoke 'foo', > then that means that the 'foo()' HLL subroutine has to be generated as: > .local pmc $P0 > $P0 = find_name_not_null 'foo' > $P0 = newclosure $P0 > $P0() > . . . > > 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. 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. > 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. As I said earlier, I'm not at all arguing that Parrot's current model is correct, or that the way I've been trying to do things is the right one -- I'm merely asking "What is the correct way to do this stuff in Parrot?" 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. > Ultimately I think that Closure PMCs need to be smart enough to take > a newclosure if they need one at the time they're invoked, rather than > trying to place that burden on the caller. (Note that I'm not arguing > that the current implementation is correct -- I'm just describing what > I think a correct implementation will need to do.) > > That's good; we semi-agree. But I'm arguing further that making parrot > guess the right context is also broken, certainly in some if not all > situations. My feeling is that the "some situations" where guessing the context is wrong will be those where the HLL compiler inserts "newclosure" opcodes to get parrot to do the right thing. I don't think that guessing will be wrong in all (or even the majority) of situations-- immediate block/sub execution is *so* much more common than the need to take an explicit closure that it feels like Parrot ought to support that model by default. If that's not Parrot's default, that's fine, but I'd like someone or a PDD to officially say that every sub with :outer *must* have a newclosure op. > I would like at least to persuade you that your badlex.pir > case is incorrect (but will settle for only semi-agreeing. ;-) As I said above, I don't have to be persuaded that badlex.pir is incorrect -- I just need to be shown what "correct" is. As I've already noted, simply replacing the symbol with a newclosure PMC doesn't work in the case of MultiSubs. > We *definitely* need newclosure; otherwise there can only ever be one > closure at a time. Except perhaps by cloning the closure, and hoping > that the runtime magic does the right thing. But I claim that compilers > can always emit code that knows what the right context is; why should > parrot *ever* have to guess? I somewhat disagree with the connotation of words here ("runtime magic", "guess") -- another name for "guess" is "default". Parrot provides a default, and we override that default when it's not the correct value/behavior. 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. (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.) > These are good examples, but AFAICS they don't pose any problems that > aren't better solved by taking an explicit newclosure, and > (re-)installing it in the namspace or MultiSub (modulo MOP issues). Fair enough. As the Rakudo lead developer, I find Ihave to work with what exists in Parrot, and "re-installing" things in MultiSubs isn't an option for me now. Nor is there any PDD or examples that I've seen that implies that this is in fact the way we expect things to work in Parrot. So, again, I'm not at all claiming that badlex.pir _should_ work -- I'm just saying that it didn't work (until Jonathan made it work) and I need to know what > Perl is the only language with the odd ability to call what ought to > be a closure before calling the outer sub, as in perl-closure-test.pl > (attached). I agree that Perl can be odd in this respect, but none of my examples or problems to date have been using this ability or requesting it. Thus far I've been simply reporting simple, common cases where we're invoking a lexically nested block within an outer block that has already been called or invoked. > 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. > 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" (although I can see how they might be taken that way). In each case I'm really trying to say "here's a HLL construct I'm trying to implement, here's the PIR that I'm trying, it doesn't work, the documentation doesn't tell me how to do it, please help." 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