In Variables§

See primary documentation in context for The my declarator.

Declaring a variable with my gives it lexical scope. This means it only exists within the current block. For example:

{
    my $foo = "bar";
    say $foo; # OUTPUT: «"bar"␤»
}
say $foo; # Exception! "Variable '$foo' is not declared"

This dies because $foo is only defined as long as we are in the same scope.

In order to create more than one variable with a lexical scope in the same sentence surround the variables with parentheses:

my ( $foo, $bar );

see also Declaring a list of variables with lexical or package scope.

Additionally, lexical scoping means that variables can be temporarily redefined in a new scope:

my $location = "outside";

sub outer-location {
    # Not redefined:
    say $location;
}

outer-location; # OUTPUT: «outside␤»

sub in-building {
    my $location = "inside";
    say $location;
}

in-building;    # OUTPUT: «inside␤»

outer-location; # OUTPUT: «outside␤»

If a variable has been redefined, any code that referenced the outer variable will continue to reference the outer variable. So here, &outer-location still prints the outer $location:

sub new-location {
    my $location = "nowhere";
    outer-location;
}

new-location; # OUTPUT: «outside␤»

To make new-location() print nowhere, make $location a dynamic variable using the * twigil. This twigil makes the compiler look up the symbol in the calling scope instead of the outer scope after trying the local scope.

my is the default scope for subroutines, so my sub x() {} and sub x() {} do exactly the same thing.

This makes it easy for the compiler take care of several things before runtime, including:

  • binding subroutine names as read-only (similar to constant)

  • reporting undeclared subroutines

  • argument checking

  • resolving multiple dispatch

  • more detailed error messages

  • optimizations

In general, when an item's visibility is directly associated with its location in the code, this makes it easier to understand and reason about the program, which enables not only a more helpful compiler but also other tools, such as IDEs and debuggers.

Also note that although declarations of constants, enumerations, modules, and types of various kinds (classes, subsets, grammars, roles) all default to package scoping (see our below), you can prefix such a declaration with my to keep it from being exposed in the API, which frees you to modify it in future revisions without breaking dependents. For example:

class Foo {                           # visible in GLOBAL
    my class ImplementationDetail {   # hidden from users of Foo
        # ...
    }
    # ...
}