[ABE.pm] perl 5.10 rules! - lexical user pragmata

Ricardo SIGNES rjbs-perl-abe at lists.manxome.org
Mon Jun 11 04:22:25 PDT 2007


That subject line probably sounds a little daunting, but this is actually a
pretty simple to use and understand feature.

A number of the 5.10 features are about making more things work in a lexical,
rather than global or dynamic, scope.  One of these things is pragmata, and
it's by making lexical pragmata user-writeable that a lot of the others are
possible.

We know what lexical scope is, and what it means for something to be
user-writeable, so then: what's a pragma?  Well, there really isn't a clear
definition, but here's my suggestion:

  A pramga is a Perl module that had an effect, possibly in limited duration,
  upon how the Perl in your program is interpreted.

The two most commonly known pragmata are "strict" and "warnings."  When strict
is in effect, you can't just say "$x = 1;" without declaring $x with (for
example) "my."

What does "in effect" mean?  Well, say we have the following program:

  use strict;

  do_something; # strict in effect

  {
    no strict;
    do_something_else; # strict not in effect

    {
      do_third_thing; # strict not in effect
      use strict;
      do_fourth_thing; # strict in effect
    }
    
    do_final_thing; # strict not in effect
  }

  finish_up; # strict in effect

Strictures are activated at the line where 'use strict' is given and continue
until the end of their lexical scope.  They work by futzing with a bitfield
value stored in the magic $^H scalar.  This wasn't very extensible: there are
only so many bitmasks to use, and anyway $^H's implementation wasn't really
guaranteed.

It's easy to writes modules that go in and out of effect:
  
  package Wrex;
  our $in_effect = 0;

  sub import   { $in_effect = 1; }
  sub unimport { $in_effect = 0; }

If we "use Wrex" then now we can check $Wrex::in_effect and see that it's true.
We can "no Wrex" and it's no longer in effect.  The problem is that these
affect a global state, meaning that once your program has two places that
import or unimport Wrex, you're likely to make yourself very confused.

To provide a system for user pragmata, perl 5.10 now has added another magic
variable: %^H.  It's just like $^H, but instead of a bitfield, it's a hash.
Further, you can get a reference to the %^H values that were in effect *at any
call frame above the current one* by using caller() and checking element ten.
You can now rewrite Wrex: 

  package wrex;

  sub import   { $^H{wrex} = 1 }
  sub unimport { $^H{wrex} = 0 }

It's easy to make this actually useful:

  package Dump;

  sub import   { $^H{Dump} = 1 }
  sub unimport { $^H{Dump} = 0 }

  sub dump {
    my $in_effect = (caller)[10];
    return unless $in_effect->{Dump};
    shift; # get the class off the stack
    print "DUMP: @_";
  }

And in your programs you can write:

  require Dump;

  Dump->dump("this won't dump");
  use Dump;
  Dump->dump("this will dump");

  {
    no Dump;

    Dump->dump("this won't dump either");
  }

  Dump->dump("but this will dump");

As of 5.10, a number of core modules have become lexical.  Some of the
high-precision math modules like bigint and bigfloat, which can impact
performance, can now be limited in scope to where they're really needed.  The
"less" module, long a joke, now stores information that can tell you what your
users want to use less of.

  if (less->of('memory')) {
    # use the caches-to-disk branch
    ...
  } else {
    # do it all in RAM
  }

Even if you never write your own lexical pragma, you're pretty likely to
benefit from their writability in the glorious 5.10 future.

-- 
rjbs


More information about the ABE-pm mailing list