Hoisting lexical declarations

7 views
Skip to first unread message

Autrijus Tang

unread,
Jul 31, 2005, 2:06:28 PM7/31/05
to perl6-c...@perl.org
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.

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. 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?

Thanks,
/Autrijus/

Larry Wall

unread,
Aug 9, 2005, 3:33:48 PM8/9/05
to perl6-c...@perl.org
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

Autrijus Tang

unread,
Aug 9, 2005, 3:56:21 PM8/9/05
to perl6-c...@perl.org
On Tue, Aug 09, 2005 at 12:33:48PM -0700, Larry Wall wrote:
> : 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.

Yay for sanity!

> : 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.

Right, they are the same problem, as "eval" merely compiled string into a
Code and calls it in-place.

> : 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. :-)

Please do then. :)

> Alternately, we could do the fancy thing now and just remember the actual
> limits of the variables' visibility. But only if it's fun. :-)

The fancy thing (position-counting) is likely to get out of control
rapidly under macros, so it's probably not much fun. Erroneousness
sounds much saner.

Thanks,
/Autrijus/

Reply all
Reply to author
Forward
0 new messages