Question

I am new to Perl and would like some help in understanding subroutines. In subroutines, is it the case that some variables will always be undefined? Is this because variables in subroutines are private? And so what if I wanted to then define said previously undefined variable, how would I go about doing that? Thanks in advance.

Was it helpful?

Solution

Variables in Perl are not private, but they can have a limited scope. Such as when declaring them with my inside a subroutine. The arguments to the subroutine are stored in the variable @_.

do_stuff($foo, $bar);

sub do_stuff {
    my ($first, $second) = @_;   # direct assignment
    print "First: $first, Second: $second\n";
}

The my declaration makes the variables lexically scoped to the surrounding block { ... }, which means they are protected, and they go out of scope when execution leaves the block.

Arguments to subroutines can also be accessed with the array functions shift and pop, which is commonly seen in Perl code:

sub do_stuff {
    my $first   = shift;
    my $second) = shift;    

This does the same thing, except that it also removes the elements from the @_ array.

Read more:

OTHER TIPS

In raw, unmitigated Perl, variables are global in scope. That is, they exist in your program from where you define them to the end of the script. Also, in Perl, variables spring into existence when you use them with an undefined value. In strings, this is treated as a null string. In numbers, it's treated as a zero.

Thus, in a subroutine, if you defined a variable in your main program, it's defined in your subroutine:

$foo = "Hello";
call_sub();

sub call_sub {
    print "$foo\n";
}

That will print "Hello".

However, no one should ever use Perl in this mode because it's so easy to have errors:

$name = "Bob"
print "Hello $Name!\n";

Whoops! I used $name when I defined it, and $Name when I used it. Plus, you don't want such global variables. Otherwise, your subroutines may overwrite your main program variables. Makes it really, really hard to write large complex programs.

In order to get around this, you are highly encouraged to put these two lines in your code:

use strict;
use warnings;

The use warnings; will issue a wide variety of warnings such as uninitialzed variables being treated as strings and numbers.

The use strict; makes even a bigger change. To put it simply (and incorrectly), use strict forces you to declare your variables before you can use them.

use warnings;
use strict;

my $name = "Bob"
print "Hello $Name\n";

This program won't work because $Name was never declared (you declare variables with the my keyword). You can see how that will prevent errors.

However, declaring these types of variables are known as lexically scoped variables. That is, they can go in and out of existence. If a variable is defined in a block, it will be undefined once outside of a block. Think of a block as the curly braces:

Subroutines are a block

sub foo {  # Curly brace starts the block
   ...
}          # Curly brace ends the block

This means if you define a variable in a subroutine, it's only in that subroutine.

Also, while and for loops are blocks:

for my $foo ( @foo_list ) {   # The variable $foo is only defined in this loop
   ...
}                             # End of block and end of loop

while ( my $foo = <@foo_list> ) {   # Again, $foo is only in this block
   ...
}                                   # End of the block

if ( $foo == $bar )   {        # Another block
   my $foo = 1;                # $foo is defined in the block
}                              # $foo is no longer defined

You can even use just curly braces:

my $foo = 1;
print "$foo\n"                # Prints 1
{
    my $foo = 2;              # Redefines $foo it's a different $foo!
    print "$foo\n"            # Prints 2
}                             # End of block, $foo in block is now out of scope
print "$foo\n";               # Prints 1 because the original $foo is in scope.

Let's look at this:

my $foo = 2;
my $bar = 5;
print "$foo\n";              # Prints 2
call_sub(5);                 # Prints "Foo is 5!"
print $foo\n";               # Prints 2

sub call_sub {
    my $foo = shift;         # Different $foo from main program!
    print "Foo is $foo!\n";
    print "Bar is $bar\n";   # Will print "Bar is 5" because $bar is in scope
}                            # Subroutine's $foo falls out of scope

As you can see, $bar was defined before I called the subroutine and so it's defined in the subroutine and still in scope. However, The $foo in my subroutine was redeclared, and remains until the end of the subroutine and falls out of scope. Thus, my subroutine's use of $foo won't interfere with my main program.

So, in answer to your question:

  • Always use use strict;. This will force you to declare variables before they can be used.
  • Variables are not defined until declared with my.
  • Variables can have a limited scope where they live and breath. This can be very useful. Don't sit there and declare all variables at the beginning of your program with my like you would do in Pascal. Declare them where they are used, and let them fall out of scope when they're not needed.
  • Subroutine variables are not private because a Subroutine can use an already declared variable. This is a bad idea because it allows a subroutine to override the value of a variable in your main program. So, always declare all of your subroutine variables with my to be safe.
  • Use use warnings; to warn you when you forgot to define a variable you're trying to use.

And finally, I lied, but for a very good reason. Variables in Perl are a wee bit (a lot) more complex than I presented. You have the concept of name space, package variables, and a way to localize variables are aren't even local. Even people who work with Perl for years have a hard time understanding the ramifications.

use strict; doesn't really force you to declare variables. It forces you to either use lexically scoped variables which you declare with my or use fully qualified variable names for package variables (or use our to declare those).

However, in the end, use strict; does in a way force you to declare a variable since 99% of the variables you will use in Perl will be declared with my. When you learn more about Perl, you can learn a bit more about that other 1%.

For more information, take a look at PerlSub about using my for private variables, and the take a look at PerlMod for a full discussion about package variables, using local, and (how could I forget!) the newly introduced state variables.

In general variables are defined with the my command (technically there is also some other ones like our and local but i never use them).

To define a variable type:

my $variable

if you do this in a subroutine it will make the variable you need. Its often a good idea to use the strict directive in your code:

use strict

this will give you some warnings when you are forgetting to define things.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top