Do-It-Yourself Lexical Pragmas
The phrase "Lexical Pragmas" is probably both redundant and ungrammatical (the correct plural of "pragma" being "pragmata", I believe). But the use of "pragma" to mean "Perl module with an all-lower-case name" is fairly common, and I wanted to make clear that this was not what I was talking about. This blog entry is about writing Perl code whose configuration changes are limited to a lexical scope, just like built-in pragmata such as strict
or warnings
.
There are two pieces to the puzzle: storing the configuration (at compile time) and reading the configuration.
Configuration seems to require a module. The usual implementation makes use of the fact that Perl's use
statement calls the module's import()
method at compile time. The import()
code needs to pick configuration information out of its arguments and store it in %^H
. This hash is global to the entire Perl program, so to prevent collisions the convention is to prepend any keys you add with the module name and a slash. So module Foo
should not add key {bar}
, but rather key {'Foo/bar'}
. You can put anything you want in this hash, but references will be stringified at run time, so don't get fancy. All the preceding also applies to the module's unimport()
method (if any) and Perl's no
statement.
The compile-time magic is that the value of %^H
your code sees is specific to the scope that called it. It is as though something like local %^H = %^H
were done for each scope entry -- but not for compile-time code, such as the import()
method when executed by use
, or any code executed in a BEGIN{}
block.
Reading your configuration requires you to be aware of what phase of execution you are in. In the compile phase, %^H
contains what you put there, including references, which I warned against two paragraphs ago. But at run-time, %^H
is empty. Instead, called code has access to the %^H
information for any enclosing call frame by calling caller()
with the appropriate argument. The eleventh returned value is a reference to the values for that call frame. So a subroutine can get its caller's values by my $hints_hash = ( caller( 0 ) )[10];
.
The sharp-eyed reader who gets this far will have noticed an inconsistency: I have been talking all along about lexical scope, but caller()
deals in call frames. What you actually get back is a reference to the contents of %^H
at the time the relevant call was compiled. Information for enclosing scopes not represented on the call stack is not accessible by this mechanism.
The fact that %^H
behaves somewhat like a localized global variable raises the question: why not just use a localized global? Besides the obvious coolness that Perl has lexical pragmas, of course. I can think of two differences:
- A lexical pragma has an interface; that is, you can process, transform, or reject a value. A localized global receives its value by assignment. You could provide an interface by
tie
-ing the variable, but that technique is a subject for another blog. - A lexical pragma's value is available at compile time.
An entirely trivial demonstration is available as a GitHub Gist.
Leave a comment