How do I use global variables safely?

G

Graham

I want to be able to allow a variable to be set in one subroutine, and use
its value in another subroutine, but I obviously can't do this if I use the
'my' or 'local' functions on the variable in each subroutine. You might say
just dispense with 'my' or 'local' and let the variable be global. Well I
was doing that and had no problem until I used ActiveState's 'Perl App' to
create a standalone executable. This doesn't seem to like global variables
and is virtually telling me I must 'use strict', and I would if I could, but
I don't know how to transfer a vairiable's value (I never did fully
understand lexical scope) Any ideas anyone?
 
K

Klaus

Graham said:
I want to be able to allow a variable to be set in one subroutine, and use
its value in another subroutine, but I obviously can't do this if I use the
'my' or 'local' functions on the variable in each subroutine.
correct.

You might say
just dispense with 'my' or 'local' and let the variable be global.

That's one solution
Well I
was doing that and had no problem until I used ActiveState's 'Perl App' to
create a standalone executable. This doesn't seem to like global variables
and is virtually telling me I must 'use strict',

I strongly support 'use strict' in any Perl program wich is longer than 2
lines of code.
and I would if I could, but
I don't know how to transfer a vairiable's value (I never did fully
understand lexical scope) Any ideas anyone?

Idea 1:
Alwayse use strict and warnings: just let the variable be global (i.e. a
package-variable) and use the correct package (that would be "$::") to acces
the variable.
==============================
use strict;
use warnings;
set_glob();
use_glob();
sub set_glob { $::glob = "xxx" }
sub use_glob { print "glob is '$::glob'\n"; }
==============================

Idea 2:
Alwayse use strict and warnings: just let the variable be global (i.e. a
package-variable) and employ "our" to make the very same global variable
accessible in each function.
==============================
use strict;
use warnings;
set_glob();
use_glob();
sub set_glob { our $glob = "xxx" }
sub use_glob { our $glob; print "glob is '$glob'\n" }
==============================

Idea 3:
Alwayse use strict and warnings: just let the variable be a lexical scope
variable (i.e. introduced by "my") outside the definition of both functions.
This lexical scope variable is then automatically accessible in each
function.
==============================
use strict;
use warnings;
my $glob;
set_glob();
use_glob();
sub set_glob { $glob = "xxx" }
sub use_glob { print "glob is '$glob'\n" }
==============================
 
M

Matt Garrish

Klaus said:
Idea 3:
Alwayse use strict and warnings: just let the variable be a lexical scope
variable (i.e. introduced by "my") outside the definition of both
functions.
This lexical scope variable is then automatically accessible in each
function.
==============================
use strict;
use warnings;
my $glob;
set_glob();
use_glob();
sub set_glob { $glob = "xxx" }
sub use_glob { print "glob is '$glob'\n" }
==============================

I personally hate using globals like that. It gives you no indication of
where the value is being set or used (except in simple examples like this),
which inevitably means sifting through lines and lines of code if something
goes wrong. My preference would be to go with the obvious:

my $glob = set_glob();
use_glob($glob);

sub set_glob { return 'xxx'; }
sub use_glob { my $temp_glob = shift; print "glob is $temp_glob\n"; }

Matt
 
G

Gunnar Hjalmarsson

Klaus said:

<three ways to use global variables snipped>

Better yet, idea 4:
Learn how to pass values between subroutines.
==============================
use strict;
use warnings;
my $var = set_var();
use_var($var);
sub set_var {
my $var = 'xxx';
return $var;
}
sub use_var {
my $var = shift;
print "var is '$var'\n";
}
==============================

See "perldoc perlsub".
 
D

Damian James

I want to be able to allow a variable to be set in one subroutine, and use
its value in another subroutine, but I obviously can't do this if I use the
'my' or 'local' functions on the variable in each subroutine. You might say
just dispense with 'my' or 'local' and let the variable be global. Well I
was doing that and had no problem until I used ActiveState's 'Perl App' to
create a standalone executable. This doesn't seem to like global variables
and is virtually telling me I must 'use strict', and I would if I could, but
I don't know how to transfer a vairiable's value (I never did fully
understand lexical scope) Any ideas anyone?

You can just declare the variable in a scope that both subs can see:
#!perl
use strict;
use warnings;
my $var;
sub foo { $var = $_[0]; }
sub bar { print "$var\n"; }
foo('test');
bar();

Though other posters have suggested methods involving passing the value
of a variable into and out of functions, and I'd recommend following their
advice.

--Damian
 
G

Graham

You can just declare the variable in a scope that both subs can see:
Silly me!. Yes, as Damian says, if I declare those variables which will be
used in more than one subroutine at the top of the file, before any
subroutines are invoked, everything is honky dory. Also, I don't think
PerlApp was forcing me to 'use strict' after all - that was another problem
which I've now overcome.

--Graham
 
D

Damian James

PerlApp was forcing me to 'use strict' after all - that was another problem
which I've now overcome.

All the same, I'd strongly suggest using strict anyway, and warnings.
It will save you time and effort in the long run.

--Damian
 
D

Dave Weaver

You can just declare the variable in a scope that both subs can see:
#!perl
use strict;
use warnings;
my $var;
sub foo { $var = $_[0]; }
sub bar { print "$var\n"; }
foo('test');
bar();

You can refine this idea further, so that the access to the variable is
restricted to certain subs only;

#!/usr/bin/perl
use strict;
use warnings;

{
# Definition of $colour restricted
# to the enclosing block;
my $colour;

# This sub can see $colour
sub set_colour {
$colour = shift;
}

# So can this
sub get_colour {
return $colour;
}
}
# No access to $colour below here

sub something_else {
...
}
 
D

Damian James

...
You can refine this idea further, so that the access to the variable is
restricted to certain subs only;
[Example with scope restricted to surrounding block]

There's MJD's article on scoping, which is a pretty thorough examination:

http://perl.plover.com/FAQs/Namespaces.html

Then there are closures:

#!/usr/bin/perl
use warnings;
use strict;

$|=1;
my $t = twirly();
select(undef,undef,undef,1/8),
print $t->() for 0..50;

sub twirly {
my $i = 0;
my @char = @_? @_ : qw{/ - \ |};
sub { "\b"x($i>0).@char[ $i++ % @char ] }
}

__END__

--Damian
 

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

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top