Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Local variable retaining value

So, I just tracked down a bug which can be demonstrated in this trivial subroutine:

sub foo {
    my $bar = shift or die "Missing bar", # <--- not a semicolon
    my @items = ();
    push @items, $bar;
    return @items;
}

Obviously the mistake is that the first line of the subroutine ends in a comma. This had some rather unusual consequences, as can be seen:

say foo(1); # 1
say foo(1); # 11
say foo(1); # 111
say foo(1); # 1111

Now, I understand that this isn't a syntax error because of how the comma operator works. I understand that @items is not being set to () because the right side of the or isn't being reached. My question is, how can a variable declared with my inside of a subroutine allow data to persist between subroutine calls? It seems as if the my is turning into an our somehow.

like image 486
AKHolland Avatar asked Jul 02 '15 18:07

AKHolland


People also ask

How are local variables stored?

Local variables are stored in memory area of the corresponding function. Scope of a variable is a program part, in which a variable can be referred to. Variables declared inside a block (at the internal level), have the block as their scope.

What is the nature of information retained by a local variable?

The reason for the limited scope of local variables is that local variables are stored in the stack, which is dynamic in nature and automatically cleans up the data stored within it. But by making the variable static with "static" keyword, we can retain the value of local variable.

What is the lifetime of a local variable?

The lifetime of a variable is the time during which the variable stays in memory and is therefore accessible during program execution. The variables that are local to a method are created the moment the method is activated (exactly as formal parameters) and are destroyed when the activation of the method terminates.

What is the default value of local variable?

There is no default value for local variables, so local variables should be declared and an initial value should be assigned before the first use.


2 Answers

B::Deparse is invaluable in exercises like this:

$ perl -MO=Deparse 31191808.pl
sub foo {
    die 'Missing bar', my(@items) = () unless my $bar = shift @_;
    push @items, $bar;
    return @items;
}

which makes this a variant of the my $var if 0 trick/bug/curiosity. Its effect is to create a lexical but static variable, which will not be reinitialized each time foo is called.

like image 151
mob Avatar answered Oct 13 '22 20:10

mob


What you are doing is very similar to this snippet :

use v5.14; # Implies strict
sub foo {
    my @something= () if 0;
    push @something, shift;
    say @something;
}

foo($_) for 1..5;

The output will be :

1
12
123
1234
12345

In Perl, conditionally declaring a variable makes it only assign a value whenever that condition is true. If you changed the if 0 to if $_[0] == 3, you'd get a completely different sequence of numbers. This is actually an old bug in Perl that cannot be fixed anymore because a lot of code might depend on it, but if you're lucky you might see this warning: "Deprecated use of my() in false conditional"

like image 20
Tom van der Woerdt Avatar answered Oct 13 '22 22:10

Tom van der Woerdt