This and other RFCs are available on the web at
  http://dev.perl.org/rfc/

=head1 TITLE

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

=head1 VERSION

  Maintainer: Nathan Wiger <[EMAIL PROTECTED]>
  Date: 07 Aug 2000
  Last Modified: 28 Aug 2000
  Mailing List: [EMAIL PROTECTED]
  Version: 2
  Number: 64
  Status: Frozen

=head1 STATUS

This RFC was relatively well-received. While many questioned how useful
C<use scope 'blocks'> could be, overall most people were quite receptive
to the C<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.

=head1 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.

=head1 MOTIVATORS

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

=head1 DESCRIPTION

=head2 Overview

First off, let's clear up what this RFC does NOT do: it does B<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 C<use strict> and 3 "little" C<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.

=head2 Different Scoping Algorithms

This RFC describes several different types of scoping. They can be used
together, yielding advanced scoping without the mess of C<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: C<subs> and C<blocks>.

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

=head3 subs

The C<subs> scoping pragma makes one key change: it automatically scopes
variables within subs as if they were C<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 C<dostuff>'s
variables had been declared with C<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 C<my>'s all over the place. 

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

=head3 blocks

The C<blocks> scoping pragma automatically scopes variables to the
innermost B<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 C<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 C<use scope
'subs'> pragma.

=head2 Incompatibility with strict

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

=head1 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.

=head1 MIGRATION

This introduces new functionality. No migration path is required.

=head1 REFERENCES

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

RFC 28: Perl should stay Perl.

Reply via email to