On Mon, Aug 01, 2005 at 02:06:28AM +0800, Autrijus Tang wrote: : Pugs did not support inline variable declarations, largely because the problem : caused by this construct: : : { : say "values of β will give rise to dom!"; : $x = $x + my $x if $x; : #1 #2 #3 #4 : } : : The evaluation order for the four $x is (#4, #2, #3, #1). However, because : $Larry made it very clear that lexical scopes are lexical, (#1, #2) must refer : to the same (outer) $x, and (#3, #4) refers to the inner $x. When implemented : naively, this creates fragmented scopes in the PIL tree. : : To simplify code generation, I propose that we float all lexical declarations : in a scope to the top of the scope, in the same place as its formal : parameters. Of course, we will still reject bogus programs like this: : : # No previous $x available here : { say $x; my $x; } : : But that means these now raises the same exception: : : sub f ($x) { my $x } : sub f { my $x; my $x } : : Alternatively, this could raise a warning and treat the second my() : as a no-op. Personally, I'm in favour of an exception.
I think the exception should certainly be the default, perhaps with the other behavior pragmatically available. But we're trying to get people to switch from = to -> anyway, and most of the places people want repeated "my" are in repeated conditionals: if my $x = foo() {...} if my $x = bar() {...} if my $x = baz() {...} So that sort of thing is likely to occur in a larger scope that is amenable to pragma. Interestingly, the "my" is actually required at the moment because we've said that assignment to an *existing* variable in a boolean context is illegal: if $x = foo() {...} # ERROR if $x = bar() {...} # ERROR if $x = baz() {...} # ERROR That's also to encourage people to write: if foo() -> $x {...} if bar() -> $x {...} if baz() -> $x {...} if that's what they mean. (And, of course, to catch the recurrent =/== error we inherited from C.) : Under this scheme, the compiler will mark variable lookups to the outer : scope explicit. The sample construct at the beginning of this post will : get compiled to this form, leaving the evaluation order explicit: : : CODE( : syms => [$x], : body => [ : SAY("values of β will give rise to dom!"), : IF( : cond => $x, : body => ASSIGN( : from => ADD( : l => $OUTER::x, : r => $x, : ), : into => $OUTER::x : ) : ); : ] : ); : : The only problem I see with it is that $CALLER::x from &ADD's position : will refer to the inner, not the outer, $x. A similar problem pops up for "eval" as well, though arguably it is the same problem if the compiler is using the CALLER mechanism to lookup variables. : However, seeing that the two : arguments are in different scopes, I think it is not worth keeping any promise : about interaction between $CALLER:: and mid-block declarations anyway. : : Does this sound sane? We can certainly declare it to be sane. :-) Or perhaps we can reserve judgement on that, and merely declare that it is insane (read: erroneous) to request variable lookup on $x from a text where it's ambiguous whether it refers to outer $x or later $x. Then we could someday do the fancy thing and resolve the ambiguity based on the (remembered) location of the eval/call itself, whereupon the blame for all the suddenly broken code will naturally slide off of our teflon-coated exteriors. Alternately, we could do the fancy thing now and just remember the actual limits of the variables' visibility. But only if it's fun. :-) Larry