Programmer's notebook: static variables in Perl

I

Irving Kimura

I'm a newcomer to Perl, and though I can already write useful
scripts, I'm still at the stage of learning about good Perl idioms.
Here I'm interested in learning more about static-like variables.

When programming C, I like using static variables to hold function-local
constants that will not change value throughout the program's
execution. E.g.

int foo( int bar, int baz ) {
static int frobozz = SOME_CONFIG_MACRO;
int retval;

/* do stuff with bar, baz, and frobozz */

return retval;
}

Here frobozz is initialized only once, no matter how often foo is
called.

In Perl, one can use block scoping to achieve a similar effect
(almost):

FOO_BLOCK:
{
my $frobozz = SOME_CONFIG_CONSTANT;

sub foo {
my ($bar, $baz) = @_;

# do stuff with $bar, $baz, and $frobozz;

$retval;
}
}

But there's a problem with this version of a static variable. If
a call to foo() happens lexically before FOO_BLOCK, then $frobozz
is undefined. This forces a potentially undesired ordering in the
placement of such sub definitions in the file.

The only way around this that I can think of is this:

FOO_BLOCK:
{
my $frobozz;

sub foo {
$frobozz ||= SOME_CONFIG_CONSTANT;
my ($bar, $baz) = @_;

# do stuff with $bar, $baz, and $frobozz;

$retval;
}
}

This means that $frobozz gets evaluated one extra time, tested,
and possibly assigned to (if SOME_CONFIG_CONSTANT happens to evaluate
to false) during every call to foo.

Is there a way to more closely replicate the behavior of C statics
than this?

TIA,

Irv
 
B

Bob Walton

Irving Kimura wrote:

....
Here I'm interested in learning more about static-like variables.

When programming C, I like using static variables to hold function-local
constants that will not change value throughout the program's
execution. E.g.

int foo( int bar, int baz ) {
static int frobozz = SOME_CONFIG_MACRO;
int retval;

/* do stuff with bar, baz, and frobozz */

return retval;
}

Here frobozz is initialized only once, no matter how often foo is
called.

In Perl, one can use block scoping to achieve a similar effect
(almost):
....


Check out the "use constant" pragma. It might be what you are looking for:

perldoc constant
 
T

Tad McClellan

Bob Walton said:
Irving Kimura wrote:


Check out the "use constant" pragma.


But that is package-scoped.

The OP wanted it block-scoped (to a function's block).
 
J

Jay Tilton

: FOO_BLOCK:
: {
: my $frobozz;
:
: sub foo {
: $frobozz ||= SOME_CONFIG_CONSTANT;
: my ($bar, $baz) = @_;
:
: # do stuff with $bar, $baz, and $frobozz;
:
: $retval;
: }
: }
:
: This means that $frobozz gets evaluated one extra time, tested,
: and possibly assigned to (if SOME_CONFIG_CONSTANT happens to evaluate
: to false) during every call to foo.
:
: Is there a way to more closely replicate the behavior of C statics
: than this?

Do the initialization in a BEGIN or INIT block.

{
my $frobozz;
INIT{ $frobozz = SOME_CONFIG_CONSTANT; }
sub foo {
my ($bar, $baz) = @_;
# do stuff with $bar, $baz, and $frobozz;
$retval;
}
}

See "Persistent Private Variables" in perlsub.
 
B

Brian McCauley

: FOO_BLOCK:
: {
: my $frobozz;
:
: sub foo {
: $frobozz ||= SOME_CONFIG_CONSTANT;
: my ($bar, $baz) = @_;
:
: # do stuff with $bar, $baz, and $frobozz;
:
: $retval;
: }
: }
:
: This means that $frobozz gets evaluated one extra time, tested,
: and possibly assigned to (if SOME_CONFIG_CONSTANT happens to evaluate
: to false) during every call to foo.
:
: Is there a way to more closely replicate the behavior of C statics
: than this?

Do the initialization in a BEGIN or INIT block.

{
my $frobozz;
INIT{ $frobozz = SOME_CONFIG_CONSTANT; }
sub foo {
my ($bar, $baz) = @_;
# do stuff with $bar, $baz, and $frobozz;
$retval;
}
}

What is the point of INIT{} there?

I can see why sometimes you'd want BEGIN{} there but I have to try
really hard to contrive a situation when...

my $frobozz;
INIT { $frobozz = SOME_CONFIG_CONSTANT; }

....is better than...

my $frobozz = SOME_CONFIG_CONSTANT;

--
\\ ( )
. _\\__[oo
.__/ \\ /\@
. l___\\
# ll l\\
###LL LL\\
 
J

Jay Tilton

: I can see why sometimes you'd want BEGIN{} there but I have to try
: really hard to contrive a situation when...
:
: my $frobozz;
: INIT { $frobozz = SOME_CONFIG_CONSTANT; }
:
: ...is better than...
:
: my $frobozz = SOME_CONFIG_CONSTANT;

Yes, if it's in a module, using either BEGIN{} or INIT{} just to give
values to variables is wasted effort. Worse, using INIT{} in a module
being require()d can be disastrous.

But it's not hard at all to create that situation when the code is in
the main program file.
 
C

Charles DeRykus

I'm a newcomer to Perl, and though I can already write useful
scripts, I'm still at the stage of learning about good Perl idioms.
Here I'm interested in learning more about static-like variables.

...
But there's a problem with this version of a static variable. If
a call to foo() happens lexically before FOO_BLOCK, then $frobozz
is undefined. This forces a potentially undesired ordering in the
placement of such sub definitions in the file.

The only way around this that I can think of is this:

FOO_BLOCK:
{
my $frobozz;

sub foo {
$frobozz ||= SOME_CONFIG_CONSTANT;
my ($bar, $baz) = @_;

# do stuff with $bar, $baz, and $frobozz;

$retval;
}
}

This means that $frobozz gets evaluated one extra time, tested,
and possibly assigned to (if SOME_CONFIG_CONSTANT happens to evaluate
to false) during every call to foo.

Is there a way to more closely replicate the behavior of C statics
than this?

You could 'require' inside a BEGIN to circumvent the ordering problem;

foo.pl:
-------
my $foobozz = SOME_CONFIG_CONSTANT;
{ sub foo { ... }
1;


BEGIN { require .foo.pl'; }
....
foo();


hth,
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,053
Latest member
BrodieSola

Latest Threads

Top