Reputation: 927
I have a "state" variable in a module method to cache the first value generated by the method. The issue is that the method keeps using the state variable value even after the object has been destroyed and a brand new object has been created and uses the method.
This really looks like a bug in the perl state variable implementation, but I'm not sure. I know I could create a module attribute to cache the value, but I'd like to do it at the method level. Here is an example:
package MyTest;
use 5.010001;
use strict;
sub new {
my $class = shift;
return bless {}, $class;
}
sub generate_id {
my $self = shift;
state $generated_id;
return $generated_id
if defined $generated_id;
$generated_id = "XYZ-" . int(rand 10000);
return $generated_id;
}
sub DESTROY {
say "Object has been destroyed";
}
1;
Here is a script calling it. As you will see, the value generated the first time by the "generate_id" method will keep coming back even after "$c" variable goes out of scope and a new one gets generated. Isn't this a bug? I thought all variable would be destroyed (including state variables) as well as method content after an object goes out of scope.
# Script.pl
use MyTest;
{
my $id_gen = MyTest->new();
say $id_gen->generate_id();
}
{
my $id_gen = MyTest->new();
say $id_gen->generate_id();
}
{
my $id_gen = MyTest->new();
say $id_gen->generate_id();
}
I get:
XYZ-6345
Object has been destroyed
XYZ-6345
Object has been destroyed
XYZ-6345
Object has been destroyed
Upvotes: 1
Views: 150
Reputation: 13664
Yes, that's the point of state
. The variable retains its state. The clue is in the name.
I thought all variable would be destroyed (including state variables) as well as method content after an object goes out of scope.
The variable would go out of scope when the method gets destroyed, yes, but the method doesn't get destroyed when the object gets destroyed. The method gets destroyed when the class gets destroyed. And classes don't really get destroyed until the program exits. (You may be able to do it with a lot of manual symbol table hacking, but I wouldn't recommend that.)
It sounds like what you want is this:
sub generate_id {
my $self = shift;
$self->{generated_id} ||= "XYZ-" . int(rand 10000);
}
Upvotes: 4
Reputation: 6840
Perl 5 doesn't have real methods, generate_id
is just a sub, which is called with the object instance as its first parameter.
So, the state variable $generated_id
is cached for the entire run of the program – and will contain the same value for any instance that you call it with.
You probably want to use an attribute for the generated ID.
Upvotes: 3