[% setvar title New pragma 'scope' to change Perl's default scoping %]

This file is part of the Perl 6 Archive

Note: these documents may be out of date. Do not use as reference!

To see what is currently happening visit http://www.perl6.org/

TITLE

New pragma 'scope' to change Perl's default scoping

VERSION

  Maintainer: Nathan Wiger <nate@wiger.org>
  Date: 7 Aug 2000
  Last Modified: 28 Aug 2000
  Mailing List: perl6-language-strict@perl.org
  Number: 64
  Version: 2
  Status: Frozen

STATUS

This RFC was relatively well-received. While many questioned how useful use scope 'blocks' could be, overall most people were quite receptive to the use scope 'subs' concept.

This RFC has been frozen. It is not expected to grow further. Since it is a pragma it is not a core piece of functionality and could be added at any time.

ABSTRACT

Historically, Perl has had the default "everything's global" scope. This means that you must explicitly define every variable with my, our, or its absolute package to get better scoping. You can 'use strict' to force this behavior, but this makes easy things harder, and doesn't fix the actual problem.

Those who don't learn from history are doomed to repeat it. Let's fix this.

MOTIVATORS

Tons of Impatience, a good amount of Laziness, and a dash of Hubris

DESCRIPTION

Overview

First off, let's clear up what this RFC does NOT do: it does NOT change Perl's default scoping. By default, Perl should be scoped globally, as it always has been and always should continue to be. Rather, this RFC suggests a pragma that will offer alternative scoping rules, to make easy things even easier.

In a default Perl script, everything is global. Which means in:

   $x = 10;
   if (1) {
      unless (undef) {
         $y = 1 if ($x);
      }
   }

$x and $y are in the same scope. This is good, but also bad. For one thing, you can hang yourself real easily if you come from a C background and expect this to keep stuff private:

   $x = 10;
   sub square {
      ($x) = @_;
      $x *= $x;
   }
   $ans = square($x);
   print "$x squared is $ans\n";  # "100 squared is 100" ?

Ooops. What happened? Turns out the sub square()'s $x is the same $x as the one outside. Bad news, you reset the (global) value of $x. Ooops.

RFC 6 addresses this problem, but in the wrong way. In Perl, you can 'use strict' to force you to predeclare all your variables with my or our (which you can do anyways if you feel like it). So the above code becomes:

   use strict;
   my $x = 10;
   sub square {
      my($x) = @_;
      $x *= $x;
   }
   my $ans = square($x);
   print "$x squared is $ans\n";

So, with the addition of use strict and 3 "little" my's, we've resolved the ambiguity. Problem is, this is a good amount of work (especially if you're Lazy *and* Impatient, like I am) for such a stupid little 5-line script. Plus, it makes the code markedly harder to read. Setting 'use strict' to the default makes easy things harder - very UN-Perlish! Eck.

The better solution is to fix the actual *problem* (Perl's scoping), and provide a method for automatically scoping variables via different algorithms than Perl's default. As Daniel Chetlin notes in RFC 16 (against strict defaults):

   Making strict 'vars' default appears to be an attempt to fix
   a hole in the floor by permanently barring access to the room
   in which the hole is, rather than just patching the hole.

Let's patch the hole.

Different Scoping Algorithms

This RFC describes several different types of scoping. They can be used together, yielding advanced scoping without the mess of my. Each of these would be specified as:

   use scope qw(types);

Where "types" are the types listed below. By default, 'all' is used, which turns on all scoping rules. As of version 1, there are currently two proposed types of scopes: subs and blocks.

Note: You can always still use an explicit my or our keyword to override the scope pragma. The scope pragma only affects variables that are not explicitly declared. This is important, since it means that no functionality is reduced by specifying use scope.

subs

The subs scoping pragma makes one key change: it automatically scopes variables within subs as if they were my'ed at the top of the sub. So, the code:

   use scope 'subs';

   sub dostuff {
       ($one, $two, $three) = @_
       if ( $two > 5 ) {
          $four = 1;
       } else {
          $five = 2;
          while ( $five < 6 ) {
              $five++;
          }
       }
       return $four || $five;
   }

Would be internally changed to the same thing as if all of dostuff's variables had been declared with my as the first statement in the sub. This keeps you from clobbering yourself with:

   ($three, $four, $five) = readvals;
   $six = dostuff($five, $three, $four);

Without the need to declare all those my's all over the place.

The exceptions to the subs scoping pragma are BEGIN, END, and any other special Perl subs that may apply.

blocks

The blocks scoping pragma automatically scopes variables to the innermost anonymous block. The key work here is anonymous. The main program itself is seen as the outermost block. So, this code:

   $x = 10;
   {
      $x = 5;
   }
   if ($x == 10) {
      $x = 25;
   }
   print "$x\n";

Would result in "25" being printed out. Here's why:

   1. The C<$x = 10> is automatically scoped with its own C<my>.

   2. The C<$x = 5> inside the B<anonymous> block is automatically
      scoped with its own C<my>.

   3. The C<$x = 25> code, however, inside the C<if> statement
      is not scoped, since it is not an B<anonymous> block. Since
      there is already an C<$x> in the current block, there is
      no need to rescope it.

Th blocks scoping pragma also works for do{} blocks, but again not for BEGIN or END (but those are subs anyways).

To illustrate, here are some examples of how this might be used:

   1. do {} block

      $val = do {
          $x = 10;
           # ... stuff happens ...
          $y;
      };

   In which case $val = $y.

   2. explicit our() scoping

      $x = 10;
      our $y = 10;
      {
         $x = 5;   # auto-my'ed
         $y += $x; # $y already our'ed above
      }
      print "$y";  # 15

Admittedly, the usefulness of this is markedly less than the use scope 'subs' pragma.

Incompatibility with strict

By its very nature, this is incompatible with strict. Specifying both use strict and <use scope> should generate an error.

IMPLEMENTATION

Hopefully simple. If you preparsed 'subs' or 'blocks' and just pseudo- inserted a "my" in front of every variable, you'd be 99% of the way there.

MIGRATION

This introduces new functionality. No migration path is required.

REFERENCES

RFC 16: Keep default Perl free of constraints such as warnings and strict.

RFC 28: Perl should stay Perl.