Perl Lines of the Day from February, 1999

I had a program with a function that expected to get an argument
$h, which was a hashref. $h had a lot of members; I
passed it by reference partly for efficiency. But inside the
function, I used $h a lot and got tired of writing
$h->{FOO_BAR} everywhere.

I added the Line of the Day as the first line of the function, and
changed all the $h->{FOO_BAR} to $h{FOO_BAR}
instead.

Some time ago, I wrote a module, Stat::lsMode which generated a string
to represent file permissions in the style of the ls -l
command. In it, I used the following monstrosity:

$permstrs[0] =~ s/([-x])$/$1 eq 'x' ? 's' : 'S'/e;

What's this for? $permstrs[0] contains a string that
represents the three user-permission bits of the file's permissions,
typically something like r-x.

Normally, if the file is user-executable, we want the last
character to be x to indicate that; otherwise, the last
character is - to show that it's not executable. However, if
the setuid bit is enabled on the file, we change x to
s and, less commonly, - to S. The line
above accomplishes this.

However, I didn't like the eval, and I kept wishing I
could use tr for what was basically a character-to-character
translation task. But I thought I couldn't use tr here,
because what came to mind was this:

$permstrs[0] =~ tr/-x/Ss/;

This is wrong because it turns r-x into rSs when
the setuid bit is on, and it should turn it into r-s.

The Line of the Day is a correct solution, and I think it's
preferable to what I had before. The lesson I learned from this is
that although lvalue substr is in my bag of tricks, it's not
as close to the top of the bag as it probably should be.

(See also 27 April 1998 item for the
appalling code that converts in the opposite direction.)

Suppose you have a compartment object $safe from the
Safe package. Normally, code evaluated in these compartments
is isolated from the main Perl variable namespace, so it can neither
read nor write the usual set of variables. This is usually what you
want from Safe compartments. But in my Text::Template module I wanted a
convenient way to let the code in the compartment see the contents of
a certain user-specified package $package. This line
accomplishes that.

Normally, this program will report that val=1, because the
Safe compartment does not have access either to the main
package or to package Q. However, after using the Line of
the Day:

$package = 'Q';
*{$safe->root . '::'} = \%{$package . '::'};

The program will report val=120, because the default root
package of the compartment has been aliased to Q.

How does this work? There's actually quite a lot of magic here.
$safe->root retrieves the name of the root of the
compartment's package namespace, typically something like
Safe::Root119. If you have a package name, and you append
::, you get the name of the hash that holds the symbol table
for that package, in this case Safe::Root119::.

On the right-hand side, we construct the name of the symbol table
for the user's package. Then we do a glob assignment to alias the
compartment's symbol table to be the user's symbol table. The effect
is that the symbol table in which the compartment is looking is the
same symbol table as the one used for the user's package.

Usually, aliasing of symbol tables in this way has no effect,
because the path through the symbol table is determined at compile
time, and once the code is compiled, a run-time aliasing like this is
too late. But in this case, the code that it's supposed to affect
hasn't been compiled yet; it is going to be compiled and executed in
the safe compartment by the $safe->reval method.

There's been discussion in comp.lang.perl.moderated about a
function that opens and reads a file and returns the contents. In
list context is should return a list of lines, and in scalar context
it should return the entire contents as a single string.

This isn't really interesting, except that in scalar context you
want to be sure you don't end up reading the file line-by-line and
then putting the lines back together. That's a waste of time.