Why subroutine needs to be written after the declaration of variables used in it?
Asked Answered
N

1

8

Let's assume we have this code, why it fails with the explicit package name error since the function is called only after the declaration of the $value?

use strict;
use warnings;

sub print_value{
    print "\n$value";
}

my $value = 2;
print_value();

This fails at compile time with :

Global symbol "$value" requires explicit package name at file.pl line 5.
Execution of file.pl aborted due to compilation errors.

And this code works perfectly fine:

use strict;
use warnings;

my $value = 2;
print_value();

sub print_value{
    print "\n$value";
}

Ignore the unutility of this programming style or the deprecated coding style, just focus on the context.

Narayan answered 6/10, 2016 at 13:10 Comment(2)
I edited the question tytle, maybe it's a bit clearer nowNarayan
Even without strict, I still wouldn't "work" -- the sub would still be using the package $value and not the lexical one declared later.Stuartstub
Q
13

It's because of scope. That's where in your program your variable is visible. Your $value is a lexical variable because you have declared it with my. That means, it exists inside a certain scope (and all the ones below that). In both of your examples that scope is the entire file (which can also be called the global scope).

Perl looks at your code in two stages. The first is compile time, where it checks the syntax and loads dependencies (like use statements). At this point, it will look for the availability of $value inside the function.

Perl will look in these places:

  1. Lexical (my and our) variables currently in scope.

    A variable is in scope (i.e. a variable is visible) if the code that references it follows the declaration, and if it's in the same block as the declaration, or block nested within that block. The file itself is a block, and curlies form the others.

    If there are multiple lexical variables with the same name in scope, the most recently declared obscure the others. That means that a variable declared in the function itself will be used before one outside the function.

    my $i;          # +--------- $i is in scope (visible) here
    my $x;          # | +------- $x is in scope (visible) here
    while (...) {   # | |
        my $j;      # | |  +---- $j is in scope (visible) here
        my $x;      # |    | +-- This different $x is in scope (visible) here 
        ...         # |    v v
    }               # | |
    sub foo {       # | |
        my $j;      # | |  +---- This different $j is in scope (visible) here
        my $x;      # |    | +-- This third $x is in scope (visible) here
        ...         # |    v v
    }               # | |
    ...             # v v
    
  2. Package variables

    These are globally variables (undeclared, or declared with use vars).

    Perl will look in the namespace declared by the latest "package" in scope (defaulting to main), except for "super-global" variables. This refers to the symbolic variables (like $_, $$, etc) for which Perl looks in main rather than the current package.

Since $value hasn't been declared, Perl takes it to mean package variable $main::value (since the main is the default package).

use strict;            # | Code here will use package var $main::value
use warnings;          # |
                       # |
sub print_value{       # |
    print "\n$value";  # |
}                      # |
                       # v
my $value = 2;         # | Code here will use this lexical var $value
print_value();         # v

None of this comes because you have strict turned on. Only the fact that you have to declare variables, either with my, or our or by using a fully qualified name is because of use strict.

If you did not have strict and did not declare the variable with my, your program would work. $value would be a package variable in that case.

In your second example you have declared $value before the subroutine, so Perl knows at compile time that there will be a $value available in that scope, so it doesn't complain.

use strict;            # | Code here will use package var $main::value
use warnings;          # |
                       # v
my $value = 2;         # | Code here will use this lexical var $value
print_value();         # |
                       # |
sub print_value{       # |
    print "\n$value";  # |
}                      # v

However, a better approach would be to pass the variable as an argument to print_value.

use strict;
use warnings;

sub print_value{
    my $arg = shift;
    print "\n$arg";
}

my $value = 2;
print_value($value);

Now Perl sees that there is a $arg inside of the small scope. It doesn't know its value, but it doesn't have to. And $value is also already declared before using it.

Never use variables from the global scope (the entire file) inside of functions. Always pass them as arguments1.


Here are some relevant links:

1) unless you want to build a singleton or some other type of closure

Quill answered 6/10, 2016 at 13:26 Comment(4)
When you say It will look at: ... the entire file scope, by entire file, you mean everything that is declared until the soubroutine declaration?Narayan
@John Yes and no. At compile time it will only know the variables that have been declared until that line it is in. That's different from the subroutine declaration. At run time the value can also be set further down in the code, but when you access it in the sub it still accesses it.Quill
Thank you for sharing all this knowledge!Narayan
When they said "It will look at the entire file scope", they misspoke. Scope is where a variable is visible. As a result, your question doesn't make sense. /// They also listed our as a package var, but it's actually lexical and thus misordered in the list. /// I'm currently fixing these problems.Volvox

© 2022 - 2024 — McMap. All rights reserved.