pritesh has asked for the wisdom of the Perl Monks concerning the following question:

Respected Monks,

I wanted to confirm if a variable delcared in a file is accessible and can be modified throughout the file, even inside a function, and that seems to be true.

pritesh@mintpad ~ $ more test_var_loc.pl use strict; use warnings; my $val = 10; print "Outside the functions \$val is $val stored at ", \$val, "\n"; sub first { $val = 200; print "In the first function \$val is $val stored at ", \$val, "\n +"; } sub second { $val = 100; print "In the second function \$val is $val stored at ", \$val, "\ +n"; } first(); print "After first function, before second function, \$val is $val st +ored at ", \$val, "\n"; second(); print "After second function, \$val is $val stored at ", \$val, "\n"; pritesh@mintpad ~ $

The output is as expected.

pritesh@mintpad ~ $ perl test_var_loc.pl Outside the functions $val is 10 stored at SCALAR(0x1c307c8) In the first function $val is 200 stored at SCALAR(0x1c307c8) After first function, before second function, $val is 200 stored at S +CALAR(0x1c307c8) In the second function $val is 100 stored at SCALAR(0x1c307c8) After second function, $val is 100 stored at SCALAR(0x1c307c8) pritesh@mintpad ~ $

Now, what I don't get is, if within the function, I declare the $val as my $val (lexical scope), no warning message is shown. Nothing like "masking earlier declaration of $val". It just treats it as if it were a different variable.

pritesh@mintpad ~ $ more test_my_var_loc.pl use strict; use warnings; my $val = 10; print "Outside the functions \$val is $val stored at ", \$val, "\n"; sub first { my $val = 200; print "In the first function \$val is $val stored at ", \$val, "\n +"; } sub second { my $val = 100; print "In the second function \$val is $val stored at ", \$val, "\ +n"; } first(); print "After first function, before second function, \$val is $val st +ored at ", \$val, "\n"; second(); print "After second function, \$val is $val stored at ", \$val, "\n";

The output is:

pritesh@mintpad ~ $ perl test_my_var_loc.pl Outside the functions $val is 10 stored at SCALAR(0xb2d7c8) In the first function $val is 200 stored at SCALAR(0xb2d888) After first function, before second function, $val is 10 stored at SC +ALAR(0xb2d7c8) In the second function $val is 100 stored at SCALAR(0xb2e290) After second function, $val is 10 stored at SCALAR(0xb2d7c8) pritesh@mintpad ~ $

I am confused. I thought that the second time I would get an error, but then it appears that, each my $var has scope limited to it's function or outside of the function. But if that's the case, I should have gotten an error the first time, stating "the variable requires explicit package name. Did you forget to declare my $var?" or something like that for the $val inside the function(s). I think I am missing something obvious here. Kindly help.

Replies are listed 'Best First'.
Re: Perl Variables storage location and scope question.
by pryrt (Abbot) on Jan 15, 2018 at 21:40 UTC
    Now, what I don't get is, if within the function, I declare the $val as my $val (lexical scope), no warning message is shown. Nothing like "masking earlier declaration of $val". It just treats it as if it were a different variable.

    see Coping with Scoping for a much better explanation than I could ever give. But I'll try, so that the explanations stay specific to what you're asking about.

    When you declare the $val as lexical scope, its lexical scope is limited to the tightest enclosing block (in this instance, the file, or the first or second functions). A deeper scope (for example, a function inside the file-scope, or a block inside the function-scope) will inherit the value from its containing scope, unless it has a lexically-scoped variable of the same name. In the first program, your only scope for $var was the file-level scope (0x1c307c8), so when you edit $var inside the functions, it's editing the file-scope variable, even from the functions. But in the second program, the first subroutine has its own lexical $val at 0xb2d888, so anything you do to that is limited to that scope; similarly, second's 0xb2e290 is limited to its own scope.

    This example shows some of the scopes, and when a "masks earlier declaration" will arise:

    use strict; use warnings; my $val = 1; print "my own scope: $val\n"; { my $val = 2; print "my own scope: $val\n"; { print "inherit: $val\n"; # this is another scope, but doesn +'t have an override of the val=2 $val = 2.5; print "edit: $val\n"; # now it's a different value } print "keep the value edited: $val\n"; # which it keeps here { my $val = 3; # this is another scope with it's +own lexical $val, so the previous $val's are invisible to me print "my own scope: $val\n"; } my $val = -2; # warning: masks earlier declaration in same scope print "when scopes collide: $val\n"; } print "back in original file scope: $val\n";
Re: Perl Variables storage location and scope question.
by kcott (Archbishop) on Jan 16, 2018 at 09:40 UTC

    G'day pritesh,

    It seems the answers you've already received cover what you're asking. However, I felt it was important to advise that this is a situation you should avoid in the first place.

    Variables with file scope, regardless of whether they're lexical or dynamic, suffer all the same classic problems as global variables: action at a distance; unclear logic; hard to debug; problematic refactoring; and so on.

    In the following demonstration script, I've reproduced all of the types of actions you're attempting, without any variables with file scope. Things to note in particular:

    • $val is declared in three separate places. Each declaration is within its own, limited scope. None of the $val variables have any relationship to any of the other $val variables.
    • &show_value is a read-only operation: it receives its data as a value. &change_value is a read-write operation: it receives its data as a reference. &unrelated_value uses its own internal, lexically isolated, data: it's called without arguments.
    • &show_value and &change_value are abstracted such that they have no dependencies on external data. They could easily be refactored into their own module.
    • &show_value is called from the main (anonymous block) code, from within &change_value, and indirectly from &unrelated_value (via &change_value). &change_value is called from the main (anonymous block) code and from &unrelated_value.

    Here's the code:

    #!/usr/bin/env perl -l use strict; use warnings; { my $val = 10; print "INIT: $val"; show_value($val); change_value(\$val, 200); show_value($val); unrelated_value(); show_value($val); print "LAST: $val"; } sub show_value { my ($val) = @_; print '* Show Value'; print "Value: $val"; return; } sub change_value { my ($val_ref, $new_value) = @_; print "* Change Value: $$val_ref to $new_value"; show_value($$val_ref); $$val_ref = $new_value; show_value($$val_ref); return; } sub unrelated_value { my $val = 42; print '* Unrelated Value'; change_value(\$val, 999); return; }

    Output:

    INIT: 10 * Show Value Value: 10 * Change Value: 10 to 200 * Show Value Value: 10 * Show Value Value: 200 * Show Value Value: 200 * Unrelated Value * Change Value: 42 to 999 * Show Value Value: 42 * Show Value Value: 999 * Show Value Value: 200 LAST: 200

    — Ken

Re: Perl Variables storage location and scope question.
by haukex (Archbishop) on Jan 16, 2018 at 08:10 UTC
    my $val (lexical scope), no warning message is shown. Nothing like "masking earlier declaration of $val".

    You can get warnings like these with Perl::Critic. While some of the advice given by that module can be ignored if one knows what one is doing, for things like this (custom warnings) it can be quite useful. For example, running it on your code gives, among other things, "Reused variable name in lexical scope: $val at line 7, column 2.  Invent unique variable names". You can promote this to a severe violation that is always reported by creating a .perlcriticrc file in your home directory that contains

    [Variables::ProhibitReusedNames] severity = 5

    And also use this file to customize other warnings, like quieting those that you don't need. Also, note you can use perlcritic --verbose 10 to get explanations of the warnings.

Re: Perl Variables storage location and scope question.
by BillKSmith (Monsignor) on Jan 16, 2018 at 05:02 UTC
    I occasionally find it useful to use the same name for a different variable in a nested scope, but far more often it is an error. I would appreciate a warning. Code to suppress the warning when required, would help make the intention clear.
    Bill
Re: Perl Variables storage location and scope question.
by ikegami (Patriarch) on Jan 17, 2018 at 17:36 UTC

    I wanted to confirm if a variable delcared in a file is accessible and can be modified throughout the file, even inside a function, and that seems to be true.

    my creates a variable that's visible in the current lexical scope (i.e. block or file).

    Nothing like "masking earlier declaration of $val". It just treats it as if it were a different variable.

    It is a different variable. And I'm also disappointed that this doesn't warn. The warning is only issued when you create two lexical variables in exactly the same scope.

Re: Perl Variables storage location and scope question.
by pritesh (Scribe) on Jan 16, 2018 at 10:35 UTC

    Respected Monks,

    Thanks a lot for your clear explanations and taking time to answer the question.