2

I have noticed many times that my code works without any bugs/issues when I do not use my to create my variables.

I will give an example (this is just an excerpt from a script);

use warnings;
use strict;

$filename=shift;
open text, $filename or die "error";

When I execute that, I get an error that goes like this:

Global symbol "$filename" requires explicit package name at script.pl line 12.

That error disappears when I change $filename=shift to my $filename=shift, and then I am able to run my code and receive the results.

However, without writing my, when I remove use warnings and use strict, the code also works normally and I get the same results from the script as I got from the one with my.

My question:

If skipping my is a mistake and leads to an error, then why does the code function properly? What is happening and what can actually happen when my is not written? Can it, in some cases, lead to bugs and strange issues?

votresignu
  • 71
  • 4
  • 7
    Does [this](https://stackoverflow.com/a/20890822/589924) answer your question? It's not about getting the program to run; it's about creating robust, maintainable programs. – ikegami Jan 29 '18 at 22:27
  • 4
    By the way, along the same lines, you should use `open my $text, ..` – ikegami Jan 29 '18 at 22:28
  • 4
    A practical take: simply _always_ have `use warnings;` and `use strict;` and consider them as built-in and not optional. So warnings and errors are precisely that and need be addressed. – zdim Jan 29 '18 at 23:14

2 Answers2

1

You are right, that without use strict you can leave away the my and the program will do its work. This is ok in a two-liner like this one:

$text_to_print = 'hello there';
print "$text_to_print\n";

But even in this example a small typo may give you an unexpected result and within a more complex program you wont be able to find it:

$text_to_print = 'hello there';
print "$text_t_print\n";
# will print an empty line only

If you add use strict; and use warnings; plus my the variable you will get warned about your typo.

use warnings;
use strict;

$text_to_print = 'hello there';
print "$text_t_print\n";
# will print to stderr: Global symbol "$text_t_print" requires explicit package name at untitled.pl line 5....
lanti
  • 529
  • 3
  • 15
1

What my does is it makes the variable lexical to the current scope. Normally in perl, variables are global, and changes to them in a scope effect all other scopes. With my, all changes to the variable are local.

There are two very clear differences between the usage of a lexical or a global variable: one is with recursive functions, and the other with closures.

If you would want to calculate something recursively (say, to calculate factorials), if you would use a global variable, each successive call to the function would clobber the previous one, leaving you with a useless function.

Here's an example in practice:

sub Factorial {
  $arg = shift; #pull the argument off
  return 1 if $first == 0; #stopping condition
  return $arg * Factorial($arg-1); #recurse
} 

This will always return 0, because as the functions recurse further towards 0, they keep clobbering the $arg variable, until it finally returns 1. But by the time it makes its way back up the chain to our value, it keeps multiplying by the global value of $arg, which is zero.

This is immediately solved with the addition of the my operator, which will make $arg lexical. This means that each call to the function has its own conception of what $arg is, allowing our recursive call to succeed.

Closures are another interesting aspect of lexical variables. It's possible to create anonymous subroutines (called lambdas in python and other languages) in perl by using sub without a name. A good use for these types of functions is to save some aspect of the current state to be used for later. (I have a heavy background in TeX, and there, closures are constantly used, it's the \edef primitive).

Closures can be used in memoization, which is saving the results of processing heavy functions in memory. An example would be as follows to create a function which memoizes another function:

sub Memoize {
  my $func = shift; #pull function name off the argument stack
  my %cache;        #prepare to memoize
  my $stub = sub {  # anonymous function
      my $key = shift; 
      $cache{$key} = $func->($key) unless exists $cache{$key};
      #this caches the result if it doesn't exist
      return $cache{$key};
    };
  return $stub;
};

This function decorates an existent one argument recursive function ref (given as \&Factorial with the functionality of memoization (practically you would want to use the Memoize module for this, but this is just to show the concept of closure). This would break horribly if not for the various lexical variables. The cache would be shared between all decorated functions. The closure here is that the value of our cache is available to any time we call the returned function, even though outside that function we can continue to use a different hash named %cache.

Both of these examples are basically taken from the book Higher Order Perl, which is excellent. It helps you understand that perl is a serious programming language, not just a way to write administrative scripts. Of course, the other answer has the practical reason for why to use strict, but there's a whole 'nother world as to what lexicals are.

If you're wondering, the way to get global variables with use strict is to precede them either with our or with main::.

A Gold Man
  • 198
  • 2
  • 7