What is the difference between `state` and `const`?

246 Views Asked by At

It seems similar to write:

use Const::Fast;
const $xx, 77;
sub test {
    do_something_with( $xx );    
}

or

sub test {
    state $xx =  77;
    do_something_with( $xx );    
}

What is the better way to accomplish this: via const or via state?

sub get_ip_country {
    my ($ip_address) = @_;
    my $ip_cc_database = GeoIP2::Database::Reader->new(file => '/etc/project/GeoLite2-Country.mmdb');
    ...
}

UPD
At this sub I do not change pointer togeoip database, so it should be const. But I not want recreate object each time when sub is called (this is slow). So I suppose it will be faster to use state, despite pointer is not changed.

It seems it should be const state $ip_cc_database

3

There are 3 best solutions below

2
On BEST ANSWER

They do not do the same thing.

  • state declares a variable that will only be initialized the first time you enter the function. It's mutable though, so you can change its value, but it will keep the value between calls to the same function. This program would for example print 78 and 79:
    sub test {
        state $xx = 77;     # initialization only happens once
        print ++$xx . "\n"; # step the current value and print it
    }
    test; # 78
    test; # 79
    
  • const declares an immutable (readonly) variable that, if declared in a function, would be reinitialized every time the function is called.
3
On

If you want a value that is constant, then you should use something like Const::Fast.

But if you want a value that can be changed, but which retains its value between calls to a function, then you need a state variable.

So running, this:

sub test {
  state $x = 1;

  say $x++;
}

test() for 1 .. 10;

Gives this:

1
2
3
4
5
6
7
8
9
10

But running this:

use Const::Fast;

sub test {
  const my $x, 1;

  say $x++;
}

test() for 1 .. 10;

Gives a runtime error:

Modification of a read-only value attempted at const_test line 12.
0
On

As @TedLyngmo points out in a comment to your OP, const state is not valid Perl. const is a pragma, so works at compile time, while state is a runtime construct.

In terms of your efficiency requirement, that the GeoIP2::Database::Reader constructor is called only once, either will work. If you further want it to be read-only so that you cannot inadvertently invalidate the reference, you can still use both. const does it for you automatically, but you can duplicate that behavior with state with a layer of indirection:

sub ip_cc_database {
   state $db = GeoIP2::Database::Reader->new(file => '/etc/project/GeoLite2-Country.mmdb');
}
sub get_ip_country {
    my ($ip_address) = @_;
    my $ip_cc_database = ip_cc_database();
    ...
}

The answer to your question about when to use one over the other is a bit more nuanced.

The real difference between the two approaches is when the constructor is called. Using const it's during the compile phase, with state it's during runtime.

If you're application always calls get_ip_country, and you don't care about amortizing startup costs over the lifetime of the process, const is simpler.

However, if you don't always call get_ip_country, and creating the GeoIP2::Database::Reader object is expensive, then using state means you only pay for that cost if you need it.

There's also the user experience to consider. If your program is interactive or if it starts generating output before you need to call get_ip_country, delaying creating the object until its actually needed means your program doesn't just sit there seemingly doing nothing until all of the startup has completed.