5

I'm learning Perl and trying to understand variable scope. I understand that my $name = 'Bob'; will declare a local variable inside a sub, but why would you use the my keyword at the global scope? Is it just a good habit so you can safely move the code into a sub?

I see lots of example scripts that do this, and I wonder why. Even with use strict, it doesn't complain when I remove the my. I've tried comparing behaviour with and without it, and I can't see any difference.

Here's one example that does this:

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

use DBI;

my $dbfile = "sample.db";

my $dsn      = "dbi:SQLite:dbname=$dbfile";
my $user     = "";
my $password = "";
my $dbh = DBI->connect($dsn, $user, $password, {
   PrintError       => 0,
   RaiseError       => 1,
   AutoCommit       => 1,
   FetchHashKeyName => 'NAME_lc',
});

# ...

$dbh->disconnect;

Update

It seems I was unlucky when I tested this behaviour. Here's the script I tested with:

use strict;

my $a = 5;
$b = 6;

sub print_stuff() {
    print $a, $b, "\n"; # prints 56
    $a = 55;
    $b = 66;
}

print_stuff();
print $a, $b, "\n"; # prints 5566

As I learned from some of the answers here, $a and $b are special variables that are already declared, so the compiler doesn't complain. If I change the $b to $c in that script, then it complains.

As for why to use my $foo at the global scope, it seems like the file scope may not actually be the global scope.

Don Kirkby
  • 53,582
  • 27
  • 205
  • 286
  • 3
    As a general rule, always use tight variable scope, and move it gradually outside as you need it (when it should be available from various parts of your program). – mpapec Jun 20 '14 at 19:21
  • 7
    You are mistaken: Perl *will* raise an error under `use strict` if you don't declare a variable at any scope, including the outermost. The exception is `$a` and `$b` which are predeclared for use in `sort`, which is why they should be avoided for your own use (apart from being very poor identifiers). – Borodin Jun 20 '14 at 19:27
  • 1
    Ah , @Borodin, I think I used `$a` in my test. I will confirm on Monday. If that's the case, it answers my question. – Don Kirkby Jun 21 '14 at 05:38
  • 2
    `my` doesn't really have anything to do with `sub`. `my` can be used to declare a variable within a `sub`, but it can also be used to declare a variable within a `for` loop, or an `if` block, or any other lexical scope. Basically, stop thinking that variable scopes are in any way tied to subs. This isn't Javascript. – tobyink Jun 21 '14 at 07:25

4 Answers4

4

The addition of my was about the best thing that ever happened to Perl and the problem it solved was typos.

Say you have a variable $variable. You do some assignments and comparisons on this variable.

$variable = 5;

# intervening assignments and calculations...

if ( $varable + 20 > 25 ) # don't use magic numbers in real code
{
    # do one thing
}
else
{
    # do something else
}

Do you see the subtle bug in the above code that happens if you don't use strict; and require variables be declared with my? The # do one thing case will never happen. I encountered this several times in production code I had to maintain.

Rob K
  • 8,757
  • 2
  • 32
  • 36
  • +1 LOL I never thought of it quite that way - it's like "advanced" (errm or "in advance") spell-checking for variable names ... – G. Cito Jun 20 '14 at 20:34
3

A few points:

  • strict demands that all variables be declared with a my (or state) or installed into the package--declared with an our statement or a use vars pragma (archaic), or inserted into the symbol table at compile time.

  • They are that file's variables. They remain of no concern and no use to any module required during the use of that file.

  • They can be used across packages (although that's a less good reason.)

  • Lexical variables don't have any of the magic that the only alternative does. You can't "push" and "pop" a lexical variable as you change scope, as you can with any package variable. No magic means faster and plainer handling.

  • Laziness. It's just easier to declare a my with no brackets as opposed to concentrating its scope by specific bracketing.

    {   my $visible_in_this_scope_only;
        ...
        sub bananas {
            ...
            my $bananas = $visible_in_this_scope_only + 3;
            ...
        }
    } # End $visible_in_this_scope_only
    

(Note on the syntax: in my code, I never use a bare brace. It will always tell you, either before (standard loops) or after what the scope is for, even if it would have been "obvious".

Axeman
  • 29,660
  • 2
  • 47
  • 102
2

It's just good practice. As a personal rule, I try to keep variables in the smallest scope possible. If a line of code can't see a variable, then it can't mess with it in unexpected ways.

I'm surprised that you found that the script worked under use strict without the my, though. That's generally not allowed:

$ perl -E 'use strict; $db = "foo"; say $db'
Global symbol "$db" requires explicit package name at -e line 1.
Global symbol "$db" requires explicit package name at -e line 1.
Execution of -e aborted due to compilation errors.
$ perl -E 'use strict; my $db = "foo"; say $db'
foo

Variables $a and $b are exempt:

$ perl -E 'use strict; $b = "foo"; say $b'
foo

But I don't know how you would make the code you posted work with strict and a missing my.

Don Kirkby
  • 53,582
  • 27
  • 205
  • 286
frezik
  • 2,316
  • 15
  • 13
2

A sub controls/limits the scope of variables between the braces {} that define its operations. Of course many variables exist outside of a particular function and using lexical my for "global" variables can give you more control over how "dynamic" their behavior is inside your application. The Private Variables via my() section of perlodocperlsub discusses reasons for doing this pretty thoroughly.

I'm going to quote myself from elsewhere which is not the best thing to do on SO but here goes:

The classic perlmonks node - Variable Scoping in Perl: the basics - is a frequently consulted reference :-)

As I noted in a comment, Bruce Gray's talk at YAPC::NA 2012 - The why of my() is a good story about how a pretty expert perl programmer wrapped his head around perl and namespaces.

I've heard people explain my as Perl's equivalent to Javascript's var - it's practically necessary but, Perl being perl, things will work without it if you insist or take pains to make it do that.

ps: Actually with Javascript, I guess functions are used to control "scope" in a way that is analagous to your description of using my in sub's.

Community
  • 1
  • 1
G. Cito
  • 6,210
  • 3
  • 29
  • 42