Apocalypse 3
by Larry Wall
|
Pages: 1, 2, 3, 4, 5, 6
Editor's Note: this Apocalypse is out of date and remains here for historic reasons. See Synopsis 03 for the latest information.
RFC 025: Operators: Multiway comparisons
|
Previous Apocalypses |
This RFC proposes that expressions involving multiple chained comparisons should act like mathematician would expect. That is, if you say this:
0 <= $x < 10
it really means something like:
0 <= $x && $x < 10
The $x would only be evaluated once, however. (This is very much like
the rewrite rule we use to explain assignment operators such as $x += 3.)
I started with this RFC simply because it's not of any earthshaking importance whether I accept it or not. The tradeoff is whether to put some slight complexity into the grammar in order to save some slight complexity in some Perl programs. The complexity in the grammar is not much of a problem here, since it's amortized over all possible uses of it, and it already matches the known psychology of a great number of people.
There is a potential interaction with precedence levels, however. If we choose to allow an expression like:
0 <= $x == $y < 20
then we'll have to unify the precedence levels of the comparison operators with the equality operators. I don't see a great problem with this, since the main reason for having them different was (I believe) so that you could write an exclusive of two comparisons, like this:
$x < 10 != $y < 10
However, Perl has a built-in xor operator, so this isn't
really much of an issue. And there's a lot to be said for forcing
parentheses in that last expression anyway, just for clarity. So
unless anyone comes up with a large objection that I'm not seeing, this
RFC is accepted.
RFC 320: Allow grouping of -X file tests and add filetest builtin
This RFC proposes to allow clustering of file test operators much like some Unix utilities allow bundling of single character switches. That is, if you say:
-drwx $file
it really means something like:
-d $file && -r $file && -w $file && -x $file
Unfortunately, as proposed, this syntax will simply be too confusing. We have to be able to negate named operators and subroutines. The proposed workaround of putting a space after a unary minus is much too onerous and counterintuitive, or at least countercultural.
The only way to rescue the proposal would be to say that such operators
are autoloaded in some fashion; any negated but unrecognized
operator would then be assumed to be a clustered filetest. This would be
risky in that it would prevent Perl from catching misspelled
subroutine names at compile time when negated, and the error might
well not get caught at run time either, if all the characters in the
name are valid filetests, and if the argument can be interpreted
as a filename or filehandle (which is usually). Perhaps it would
be naturally disallowed under use strict, since we'd basically
be treating -xyz as a bareword. On the other hand, in Perl 5, all
method names are essentially in the unrecognized category until run
time, so it would be impossible to tell whether to parse the minus
sign as a real negation. Optional type declarations in Perl 6 would
only help the compiler with variables that are actually declared to
have a type. Fortunately, a negated 1 is still true, so even if we
parsed the negation as a real negation, it might still end up doing
the right thing. But it's all very tacky.
So I'm thinking of a different tack. Instead of bundling the letters:
-drwx $file
let's think about the trick of returning the value of $file for a true
value. Then we'd write nested unary operators like this:
-d -r -w -x $file
One tricky thing about that is that the operators are applied right
to left. And they don't really short circuit the way stacked && would
(though the optimizer could probably fix that). So I expect we could
do this for the default, and if you want the -drwx as an autoloaded
backstop, you can explicitly declare that.
In any event, the proposed filetest built-in need not be built in.
It can just be a universal method. (Or maybe just common to strings
and filehandles?)
My one hesitation in making cascading operators work like that is that people might be tempted to get cute with the returned filename:
$handle = open -r -w -x $file or die;
That might be terribly confusing to a lot of people. The solution to this conundrum is presented at the end of the next section.
RFC 290: Better english names for -X
This RFC proposes long names as aliases for the various filetest operators, so that instead of saying:
-r $file
you might say something like:
use english;
freadable($file)
Actually, there's no need for the use english, I expect. These names
could merely universal (or nearly universal) methods. In any case, we
should start getting used to the idea that mumble($foo) is
equivalent to $foo.mumble(), at least in the absence of a local
subroutine definition to the contrary. So I expect that we'll see
both:
is_readable($file)
and:
$file.is_readable
Similar to the cascaded filetest ops in the previous section, one approach might be that the boolean methods return the object in question for success so that method calls could be stacked without repeating the object:
if ($file.is_dir
.is_readable
.is_writable
.is_executable) {
But -drwx $file could still be construed as more readable,
for some definition of readability. And cascading methods aren't
really short-circuited. Plus, the value returned would have to be
something like ``$file is true,'' to prevent confusion over filename ``0.''
There is also the question of whether this really saves us anything
other than a little notational convenience. If each of those methods
has to do a stat on the filename, it will be rather slow. To fix
that, what we'd actually have to return would be not the filename,
but some object containing the stat buffer (represented in Perl 5 by
the _ character). If we did that, we wouldn't have to play
$file is true games, because a valid stat buffer object would
(presumably) always be true (at least until it's false).
The same argument would apply to cascaded filetest operators we talked
about earlier. An autoloaded -drwx handler would presumably be
smart enough to do a single stat. But we'd likely lose the speed gain
by invoking the autoload mechanism. So cascaded operators
(either -X style or .is_XXX style) are the way to go.
They just return objects that know how to be either boolean or stat
buffer objects in context. This implies you could even say
$statbuf = -f $file or die "Not a regular file: $file";
if (-r -w $statbuf) { ... }
This allows us to simplify the special case in Perl 5 represented by
the _ token, which was always rather difficult to explain. And
returning a stat buffer instead of $file prevents the confusing:
$handle = open -r -w -x $file or die;
Unless, of course, we decide to make a stat buffer object return the filename
in a string context. :-)

