Statement modifier scope

2 views
Skip to first unread message

Paul Seamons

unread,
Apr 15, 2005, 1:50:52 PM4/15/05
to perl6-l...@perl.org
The following chunks behave the same in Perl 5.6 as in Perl 5.8. Notice the
output of "branching" statement modifiers vs. "looping" statement modifiers.

perl -e '$f=1; {local $f=2; print "$f"} print " - $f\n"'
# prints 2 - 1

perl -e '$f=1; {local $f=2 if 1; print "$f"} print " - $f\n"
# prints 2 - 1

perl -e '$f=1; {local $f=2 unless 0; print "$f"} print " - $f\n"''
# prints 2 - 1

perl -e '$f=1; {local $f=2 for 1; print "$f"} print " - $f\n"'
# prints 1 - 1

perl -e '$f=1; {local $f=2 until 1; print "$f"} print " - $f\n"'
# prints 1 - 1

perl -e '$f=1; {local $f=2 while !$n++; print "$f"} print " - $f\n"'
# prints 1 - 1

It appears that there is an implicit block around statements with looping
statement modifiers. perlsyn does state that the control variables of the
"for" statement modifier are locally scoped, but doesn't really mention that
the entire statement is as well. I'm not sure if this was in the original
design spec or if it flowed out of the implementation details, but either way
it seems to represent an inconsistency in the treatment of locality with
regards to braces (ok I guess there are several in Perl5).

So the question is, what will it be like for Perl6. It would seem that all of
the following should hold true because of scoping being tied to the blocks.

pugs -e 'our $f=1; {temp $f=2; print $f}; say " - $f"'
# should print 2 - 1 (currently prints 2 - 2 - but that is a compiler
issue)

pugs -e 'our $f=1; {temp $f=2 if 1; print $f}; say " - $f"'
# should print 2 - 1 (currently dies with parse error)

pugs -e 'our $f=1; {temp $f=2 for 1; print $f}; say " - $f"'
# hopefully prints 2 - 1 (currently dies with parse error)

As a side note - pugs does work with:

pugs -e 'our $f=1; {$f=2 for 1; print $f}; say " - $f"'
# prints 2 - 2 (as it should. It seems that statement modifiers don't
currently work with declarations - but that is a compiler issue - not a
language issue.)

I have wanted to do this in Perl5 but couldn't but would love to be able to do
in Perl6:

my %h = <a 1 b 2 c 3>;
{
temp %h{$_} ++ for %h.keys;
%h.say; # values are incremented still
}
%h.say; # values are back to original values

Paul

Juerd

unread,
Apr 15, 2005, 1:57:52 PM4/15/05
to Paul Seamons, perl6-l...@perl.org
Paul Seamons skribis 2005-04-15 11:50 (-0600):

> my %h = <a 1 b 2 c 3>;
> {
> temp %h{$_} ++ for %h.keys;

Just make that two lines. Is that so bad?

temp %h;
%h.values »++;

> %h.say; # values are incremented still
> }
> %h.say; # values are back to original values


Juerd
--
http://convolution.nl/maak_juerd_blij.html
http://convolution.nl/make_juerd_happy.html
http://convolution.nl/gajigu_juerd_n.html

Juerd

unread,
Apr 15, 2005, 2:28:55 PM4/15/05
to Paul Seamons, perl6-l...@perl.org
Paul Seamons skribis 2005-04-15 12:16 (-0600):
> For the given example, your code fits perfectly. A more common case I have
> had to deal with is more like this:

> my %h = <a 1 b 2 c 3>
> my %other = <a one b two>;
> {
> temp %h{$_} = %other{$_} for %other.keys;

Either

temp %h;
%h{$_} = %other{$_} for %other.keys;

or

temp %h;
%h{ %other.keys } = %other.values;

or even

temp %h{ %other.keys } = %other.values;

should work well already?

> %h.say;
> }

I think it's hard to find an example that can't easily be rewritten as
something that already works. Gather/take solves most.

Paul Seamons

unread,
Apr 15, 2005, 2:16:30 PM4/15/05
to perl6-l...@perl.org
On Friday 15 April 2005 11:57 am, Juerd wrote:
> Paul Seamons skribis 2005-04-15 11:50 (-0600):
> > my %h = <a 1 b 2 c 3>;
> > {
> > temp %h{$_} ++ for %h.keys;
>
> Just make that two lines. Is that so bad?
>
> temp %h;
> %h.values »++;
>

For the given example, your code fits perfectly. A more common case I have

had to deal with is more like this:

my %h = <a 1 b 2 c 3>


my %other = <a one b two>;
{
temp %h{$_} = %other{$_} for %other.keys;

%h.say;
}

Ideally that example would print
a one
b two
c 3

It isn't possible any more to do something like
{
temp %h = (%h, %other);
}
because that second %h is now hidden from scope (I forget which Apocalypse or
mail thread I saw it in). Plus for huge hashes it just isn't very efficient.

I'd like to temporarily put the values of one hash into another (without
wiping out all of the modfied hashes values like "temp %h" would do), run
some code, leave scope and have the modified hash go back to normal. In
perl5 I've had to implement that programatically by saving existing values
into yet another hash - running the code - putting them back. It works but
there is all sorts of issues with defined vs exists.

So yes - your code fits the limited example I gave. But I'd still like the
other item to work.

Paul

Paul Seamons

unread,
Apr 15, 2005, 2:41:06 PM4/15/05
to perl6-l...@perl.org
>
> temp %h;
> %h{ %other.keys } = %other.values;
>
> or even
>
> temp %h{ %other.keys } = %other.values;
>
> should work well already?

Almost - but not quite.

In Perl5
perl -MData::Dumper -e '%h=qw(a 1 b 2); {local %h; $h{a}="one"; print Dumper
\%h} print Dumper \%h;
$VAR1 = {
'a' => 'one'
};
$VAR1 = {
'a' => '1',
'b' => '2'
};

I'm imaging the behavior would be the same with Perl6. Notice that 'b' is
gone in the first print. I only want to temporarily modify "some" values
(the ones from the %other hash). I don't want the contents of the %h to be
identical to %other - I already have %other.

So in Perl5 this does work:

perl -MData::Dumper -e '%h=qw(a 1 b 2); {local %h=%h; $h{a}="one"; print
Dumper \%h} print Dumper \%h;
$VAR1 = {
'a' => 'one'
'b' => '2',
};
$VAR1 = {
'a' => '1',
'b' => '2'
};
But this won't work in Perl6 (temp $var = $var doesn't work in Perl6) and
again it may be fine for small hashes with only a little data - but for a
huge hash (1000+ keys) it is very inefficient.

This is good discussion - but it isn't the real focus of the original message
in the thread - the question is about the local (temp) scoping of looping
statement modifiers in Perl6.

Though, I do appreciate your trying to get my example working as is.

Paul

Paul Seamons

unread,
Apr 15, 2005, 2:51:46 PM4/15/05
to perl6-l...@perl.org
On Friday 15 April 2005 12:28 pm, Juerd wrote:
> temp %h{ %other.keys } = %other.values;

Oops missed that - I like that for solving this particular problem. It does
even work in Perl5:

perl -MData::Dumper -e '%h=qw(a 1 b 2); {local @h{qw(a b)}=("one","two");

print Dumper \%h} print Dumper \%h'
$VAR1 = {

'a' => 'one',
'b' => 'two'


};
$VAR1 = {
'a' => '1',
'b' => '2'
};

I had never thought to do a hash slice in a local. That is great!!!

Thank you very much! Wish I'd know about that three years ago.

But, it still doesn't answer the original question about scoping in the
looping statement modifiers.

Paul

Larry Wall

unread,
Apr 15, 2005, 3:24:23 PM4/15/05
to perl6-l...@perl.org
I would like to get rid of all those implicit scopes. The only
exception would be that any topicalizing modifier allocates a private
lexical $_ scoped to just that statement. But dynamic scoping may
happen only at explicit block boundaries.

I can see the argument for the other side, where any "deferred"
code is treated as a kind of closure regardless of whether there are
explicit curlies around it. That would solve certain problems like
defining the scopes of the lexicals in

$a = $x ?? my $y :: my $z;

or the infamous

my $x = 1 if $y;

to extend only to the subexpressions in which they find themselves.
But it's not what naive users expect, and it's hard to explain, so I
think we should stick with explicit curlies for most of our scoping
needs, even if it means letting certain variables hang around undefined
because their initialization was never executed.

Larry

Paul Seamons

unread,
Apr 15, 2005, 3:42:07 PM4/15/05
to perl6-l...@perl.org
> I'm imagining it will be different, as I expect temp to not hide the old
> thing. I'm not sure it will.

That is another good question. I just searched through the S and A's and
couldn't find if temp will blank it out. I am thinking it will act like
local. Each of the declarations my, our and local currently set the value to
undefined (unless set = to something). I imagine that temp and let will
behave the same.

In which case "local %h;" and "let %h" would allocate a new, empty variable in
a addition to the original variable (which is hidden but still retains its
contents).

Paul

Juerd

unread,
Apr 15, 2005, 3:15:17 PM4/15/05
to Paul Seamons, perl6-l...@perl.org
Paul Seamons skribis 2005-04-15 12:41 (-0600):

> In Perl5
> perl -MData::Dumper -e '%h=qw(a 1 b 2); {local %h; $h{a}="one"; print Dumper
> \%h} print Dumper \%h;
> $VAR1 = {
> 'a' => 'one'
> };
> $VAR1 = {
> 'a' => '1',
> 'b' => '2'
> };
> I'm imaging the behavior would be the same with Perl6. Notice that 'b' is

I'm imagining it will be different, as I expect temp to not hide the old


thing. I'm not sure it will.

Juerd

unread,
Apr 15, 2005, 5:14:40 PM4/15/05
to Paul Seamons, perl6-l...@perl.org
Paul Seamons skribis 2005-04-15 13:42 (-0600):

> Each of the declarations my, our and local currently set the value to
> undefined (unless set = to something).

That's not true.

use strict;
$::foo = 5;
our $foo;
print $foo; # 5

Reply all
Reply to author
Forward
0 new messages