Re: A curious case of of my()
by moritz (Cardinal) on Apr 05, 2011 at 09:23 UTC
|
| [reply] |
Re: A curious case of of my()
by JavaFan (Canon) on Apr 05, 2011 at 09:40 UTC
|
So my question is that why @array is behaving like a static variable in C language here?
It's an artifact of the implementation (and in particular, with an optimization). my has compile-time and run-time effects, and due to the if statement, not all run-time effects happen. As pointed out before, don't rely on it - it may not work like this in the future. And it may not work as expected now either - it won't act like a static C variable if you use recursion:
#!/usr/bin/perl
use 5.010;
use strict;
use warnings;
sub foo {
my $x if 0;
say ++$x;
}
sub bar {
my $x if 0;
say ++$x;
bar() if @_;
}
foo;
foo;
bar(1);
__END__
Deprecated use of my() in false conditional at ./x line 10.
Deprecated use of my() in false conditional at ./x line 15.
1
2
1
1
Note that the second time bar() is called (due to recursion), you do get a different $x - unlike the foo() case.
Since 5.10, there is a warning on my $foo if 0; (at compile time). People have argued there should always be a warning on any my $foo if EXPR or my $foo = EXPR1 if EXPR2; usage, but that hasn't happened, and isn't happening in blead either.
Also since 5.10, if you want a static variable, you can use the state keyword. | [reply] [d/l] [select] |
|
|
Thanks JavaFan and LanX.
Points on compile-time and run-time difference are well taken.
BTW, in my original code, I do use strict/warning,
and knew that separating the declaration and condition statement makes it work as expected. But still knowing a little more about what is going on under the hood is more satisfactory.
| [reply] |
Re: A curious case of of my()
by Anonymous Monk on Apr 05, 2011 at 08:38 UTC
|
| [reply] |
Re: A curious case of of my()
by ikegami (Patriarch) on Apr 05, 2011 at 15:17 UTC
|
It's quite simple: Using a my variable without having first executed the my is a bug. By braking that rule, you break the "fourth wall" between the promised behaviour of my and its optimised implementation.
my variables are created at compile time. Executing a my places a directive on the stack that will get executed on scope exit. The directive causes the variable to be cleared (if possible) or replaced (if a reference keeps it alive).
If you want a static variable, use state.
| [reply] [d/l] [select] |
|
|
use strict;
use warnings;
$a=0;
if ($a) {
my $z=666;
}
my $y=666 if $a;
print $y; # -> nothing
print $z; # -> Global symbol "$z" requires explicit package na
+me
of course treating short circuit and in the same way could cause more complications.
$a and my $x =666;
print $x; # -> nothing
At least this "it's a new scope" logic could be used to detect "my"-problems at compile-time and throw warnings.
UPDATE: short-circuit and | [reply] [d/l] [select] |
|
|
foo() and my $x;
foo() or my $x;
foo() && my $x;
foo() || my $x;
foo() // my $x;
foo() ? my $x : 1;
Not to mention that some code relies on the current behaviour.
| [reply] [d/l] |
|
|
|
|
Re: A curious case of of my()
by kilocoder (Novice) on Apr 05, 2011 at 16:42 UTC
|
$href is empty, since it is not passed into foo.
hence @array ends up being a package variable and not a lexical variable.
your code sub foo{
my $var = shift;
my $href = shift;
my @array = $href->{pass_in} if defined $href and exists $href
+->{pass_in};
push @array, $var;
print "contents : @array\n";
}
foo(1);
foo(2);
This gives
contents : 1
contents : 1 2
However, commenting out the unused href code and declaring array as a lexical like: sub foo{
my $var = shift;
my @array;
#my $href = shift;
#my @array = $href->{pass_in} if defined $href and exists $hre
+f->{pass_in};
push @array, $var;
print "contents : @array\n";
}
foo(1);
foo(2);
gives
contents : 1
contents : 2
I hope for nothing. I fear nothing. I am free.
| [reply] [d/l] [select] |
|
|
our @array; # package vaiable
@array = qw( foo bar );
sub foo{
my $var = shift;
my $href = shift;
my @array = $href->{pass_in} if defined $href and exists $href
+->{pass_in};
push @array, $var;
print "contents : @array\n";
}
print "outer scope - contents : @array\n";
foo(1);
foo(2);
print "outer scope - contents : @array\n";
__END__
outer scope - contents : foo bar
contents : 1
contents : 1 2
outer scope - contents : foo bar
As you can see, the variable @array inside the sub is a lexical. | [reply] [d/l] |
| A reply falls below the community's threshold of quality. You may see it by logging in. |