NAME
perlsecret - Perl secret operators and constants
SYNOPSIS
Perl secret operators:
Operator Nickname Function
====================================================
0+ Venus numification
@{[ ]} Babycart list interpolation
!! Bang bang boolean conversion
}{ Eskimo greeting END block for one-liners
~~ Inchworm scalar
~- Inchworm on a stick high-precedence decrement
-~ Inchworm on a stick high-precedence increment
-+- Space station high-precedence numification
=( )= Goatse scalar / list context
=< >=~ Flaming X-Wing match input, assign captures
~~<> Kite a single line of input
<<m=~m>> m; Ornate double-bladed sword multiline comment
-=! -=!! Flathead conditional decrement
+=! +=!! Phillips conditional increment
x=! x=!! Pozidriv conditional reset to ''
*=! *=!! Torx conditional reset to 0
,=> Winking fat comma non-stringifying fat comma
()x!! Enterprise boolean list squash
0+!! Key to the truth numeric boolean conversion
||() Abbott and Costello remove false scalar from list
Perl secret constants:
Constant Nickname Value
======================================================
<=><=><=> Space fleet 0
<~> Amphisbaena $ENV{HOME}
DESCRIPTION
Perl has a long tradition of giving nicknames to some of its operators (possibly a form of Huffmanisation). These nicknames are based on the appearance of the operator, rather than its function. The well-known examples are the diamond operator (<>
), nicknamed by Geneva Wall and the spaceship operator (<=>
), nicknamed by Randal Schwartz. Some lesser known Perl operators with a nickname are the fat comma (=>
) and yada yada (...
).
The Perl "secret operators" have been discovered (or created) by Perl obfuscators and golfers, usually when looking for a shorter way to perform a given operation. Secret operators are not actually secret, and they are not actually operators either. The perl parser does not specifically recognise them, and no one is trying to hide them from you. But they are like operators in the sense that these Perl programmers see them often enough to recognize them without thinking about their smaller parts, and eventually add them to their toolbox. And they are like secrets in the sense that they have to be discovered by their future user (or be transmitted by a fellow programmer), because they are not explicitly described in the Perl core documentation.
Because secret operators are not operators they don't have real names, and so they need nicknames. Like the above Perl operators, their name is usually related to their shape.
The term "secret operator" was probably coined by Abigail in a comp.lang.perl.misc
post in January 2003.
A word of warning
Many of those "operators" are not suitable for production code, because they are obscure to the uninitiated, although some are just names for common idioms. The really secret operators are used by golfers, obfuscators and people who like to have fun with their favorite programming language.
You're welcome to try these at home, but they might not be safe for work!
SECRET OPERATORS
The following section presents the Perl secret operators, with some historical context, an explanation of how they work and examples of use.
Venus
0+
+0
The Venus operator is a name given to a very common idiom. It performs the numification of the value on its right/left, depending of the version used. (This is accomplished by using the identity element for the addition).
print 0+ '23a'; # 23
print 0+ '3.00'; # 3
print 0+ '1.2e3'; # 1200
print 0+ '42 EUR'; # 42
print 0+ 'two cents'; # 0
$ref = [];
print 0+ $ref, ' ', "$ref"; # 164094424 ARRAY(0x9c7e1d8)
print 0+ $!, ' ', $!; # 2 No such file or directory
Note that 0+
is the method name used for "numeric conversion" by the overload
module.
Baby cart
@{[ ]}
Discovered by Larry Wall, 1994. (Alternate nicknames: "shopping-trolley", "pram", "turtle")
The baby cart operator performs list interpolation inside a string. The list items are separated by the value of $"
.
# SQL in a heredoc
local $" = ',';
my $sth = $self->execute( << "SQL" );
SELECT id, name, salary
FROM employee
WHERE id IN (@{[ keys %employee ]})
SQL
# process args in %arg
# and spit out the unknown ones
die "Uuh?: @{[ sort keys %arg ]}\n"
Another use case is for breaking aliasing (i.e. make a copy); for example to avoid the Modification of a read-only value attempted
fatal error when running such code:
for (qw( 1 2 3 )) {
$_ = $_ * $_; # contrived
print "square: $_\n";
}
With the babycart, the topic is an actually modifiable copied scalar.
for ( @{[ qw( 1 2 3 ) ]} ) {
$_ = $_ * $_; # contrived
print "square: $_\n";
}
This is a container, or circumfix operator. The expression inside the []
is run in list context, stored in an anonymous array, which is immediately dereferenced by @{}
.
You will see this occasionally in production code.
Bang bang
!!
This operator was in common usage by C programmers even before Perl existed. It performs boolean conversion, by performing logical negation twice.
my $true = !! 'a string'; # now 1
my $false = !! undef; # now ''
Eskimo greeting
}{
Discovered by Abigail, in 1997.
The eskimo greeting operator is an END
block for one-liners.
The following program counts and prints the number of lines in the input:
$ perl -lne '}{print$.'
The Eskimo greeting abuses the way the -p and -n options generate Perl code (as shown by using the B::Deparse
module):
$ perl -MO=Deparse -lne '}{print$.'
-e syntax OK
BEGIN { $/ = "\n"; $\ = "\n"; }
LINE: while (defined($_ = <ARGV>)) {
chomp $_;
}
{
print $.;
}
The discovery was done after The Perl Journal published an interview with Chip Salzenberg, in which he explained what hack perl uses to implement -p
and -n
.
Ethnographic note: in modern Western culture, an eskimo kiss is the act of pressing the tip of one's nose against another's. It is loosely based on a traditional Inuit greeting called a kunik, that early explorers of the Arctic dubbed "Eskimo kissing" when they first witnessed it. The kunik itself is not a kiss, not erotic, and simply of form of affectionate greeting.
Inchworm
~~
This operator is basically a shorter scalar
(shaves 4 characters!) using the same idea as the secret bang bang operator.
$ perl -Esay~~localtime
Tue Mar 13 19:53:25 2012
The inchworm looks very much like the smart-match operator introduced in Perl 5.10, but since it's actually a sequence of two unary operators, the Perl parser can't mix it up with the binary smart-match.
Note that Perl's ~
is operand sensitive: if its operand has a numeric value (either because it was assigned a number, the result of a numeric operation, or had been used in numeric context), it is a numeric bitwise negation (first implicitly converting to unsigned integer (UV), or under the scope of use integer
, signed integer (IV)); otherwise it is a string bitwise negation.
And this explains how it differs from !!
. Instead of forcing the operand into some kind of boolean, it forces it into some kind of either string or number (depending on the operand).
Thus, for most inputs, the inchworm acts just like scalar()
.
Examples of exceptions:
# floating point
$x = 1.23;
print ~~$x; # 1
# string used in numeric context
$x = "1.23";
print ~~$x if $x != 0; # 1
# integer out of range
use Config '%Config';
$x = 2**( 8 * $Config{uvsize} );
print ~~$x; # UV_MAX
$x = -1;
print ~~$x; # UV_MAX
$x = 2**( 8 * $Config{uvsize} - 1 );
{
use integer;
print ~~$x; # IV_MIN
}
$x = -2**( 8 * $Config{uvsize} - 1 ) - 1;
{
use integer;
print ~~$x; # IV_MIN
}
But it is also handy as a shorthand to get stringification from objects that overload it in some useful way:
use DateTime;
use JSON;
my $now = DateTime->now;
print encode_json { time => ~~$now };
Inchworm on a stick
~-
-~
Discovered by Ton Hospel, 2002.
These two operators perform a high-precedence decrement (~-
) and high-precedence increment (-~
) on integers (on a two's-complement architecture). It's a trick that assembly language programmers have been using for decades.
In C, Python and Ruby, they work on all integers. Due to how ~
is implemented in Perl (a little known fact is that Perl's bitwise operators cast operands to unsigned integers without use integer
and to signed integers with use integer
), this pair of secret operators is limited to signed integers. It's actually even more limited by default: ~-
only decrements integers greater than 0, and -~
only increments integers lesser than 0. To get the inchworms on a stick to work on all signed integers, they must be used under the scope of use integer
, so that signed integers are used everywhere in bitwise operations.
This golfing technique allows to get rid of a pair of parentheses:
$y = ~-$x * 4; # identical to $y = ($x-1)*4;
Here's the proof:
$x - 1 == - ( -$x ) - 1
In two's complement architectures, to get the opposite of a number, all you need to do is flip all bits, and add 1. I.e.,
-$i == ~$i + 1
Using this to replace - ( -$x )
in the above identity, we get:
$x - 1 == ( ~-$x + 1 ) - 1
And after eliminating the ones from the equation,
$x - 1 == ~-$x
QED.
For -~
, the proof is similar:
$x + 1 == - ( -$x ) + 1
$x + 1 == - ( ~$x + 1 ) + 1
$x + 1 == -~$x - 1 + 1
$x + 1 == -~$x
In both versions, the high precedence comes from the fact that ~
and unary -
both have higher precedence than all other arithmetic operators (except **
).
Mnemonic: the backwards-facing inchworm on a stick (~-
) decrements, and the forward-facing inchworm on a stick (-~
) increments.
Space station
-+-
Discovered by Alistair McGlinchy, 2005.
This operator performs a high precedence numification.
print -+- '23a'; # 23
print -+- '3.00'; # 3
print -+- '1.2e3'; # 1200
print -+- '42 EUR'; # 42
$ref = [];
print -+- $ref, ' ', "$ref"; # 151097816 ARRAY(0x90191d8)
print -+- $!, ' ', $!; # 2 No such file or directory
At first, this looks exactly like the Venus operator. However, because the Venus operator uses a binary +
, it has a lower precedence than the multiplicative operators like *
or x
. On the other hand, the space station operator is the concatenation of three unary operators, and therefore has higher precedence.
In the following example, we'll try to print the numification of the string '20GBP'
(i.e. '20'
) repeated three times.
# wrong: prints the numification of '20GBP20GBP20GBP'
print 0+ '20GBP' x 3; # 20
# wrong: does the equivalent of ( print '20' ) x 3
print( 0+ '20GBP' ) x 3; # 20
# right: but too lengthy, too lispy
print( ( 0 + '20GBP' ) x 3 ); # 202020
# right: uses the space station operator
print -+- '20GBP' x 3; # 202020
However, because unary minus simply replace the initial -
or +
of a string, by its counterpart, the space station does not numify strings starting with a minus or strings that do not start with a number:
print -+- 'two cents'; # +two cents
print -+- '-2B' x 5; # -2B-2B-2B-2B-2B
In the above example, -+- '-2B'
produces the string '-2B'
, whereas 0+ '-2B'
would have given the expected number (-2
).
Goatse
=( )=
(Alternate nickname: "Saturn")
If you don't understand the name of this operator, consider yourself lucky. You are advised not to search the Internet for a visual explanation.
The goatse operator provides a list context to its right side and returns the number of elements to its left side. Note that the left side must provide a scalar context; obviously, a list context on the left side will receive the empty list in the middle.
The explanation is that a list assignment in scalar context returns the number of elements on the right-hand side of the assignment, no matter how many of those elements were actually assigned to variables. In this case, all the elements on the right are simply assigned to an empty list (and therefore discarded).
# count the words in $_
$n =()= /word1|word2|word3/g;
# $n = 1
$n =()= "abababab" =~ /a/;
# $n = 4
$n =()= "abababab" =~ /a/g;
The goatse operator is a container (sic), so it can also be used to assign values from the right-hand side to the variables inside it.
# $n = 4; $b = 'a'
$n =($b)= "abababab" =~ /a/g;
# $n = 4; @c = qw( a a a a )
$n =(@c)= "abababab" =~ /a/g;
In some cases, the full goaste is not needed, because there is no need to store the value in a variable. The side-effect of list assignment in scalar context can be obtained with a right-handed goaste (()=
) used in a scalar context provided by some other mean than assignement to a scalar. For example:
# remove empty array refs
@arrays = ( [], [1], [ 1, 2 ], [], [ 5 .. 9 ] );
# @filled = ( [1], [ 1, 2 ], [ 5 .. 9 ] );
@filled = grep +()= @$_, @arrays;
(The +
is in the above line is a no-op, used to tell grep
that the parentheses are not enclosing its arguments.)
Here's a convoluted example where =()=
seems to be the proper construct to use, but it's actually another secret operator that really does the trick.
Imagine you want to know in how many elements split()
would split a string, but do not care about the elements themselves. Using split()
in scalar context:
my $count = split /:/, $string;
Gives the correct answer, but also a warning:
Use of implicit split to @_ is deprecated
Using =()=
to force scalar context on the left side (to get the number of substrings) and list context on the right side (to avoid the deprecated not-in-list-context construct) seems like the proper solution:
my $count =()= split /:/, $string;
It does not warn indeed, but always returns 1
(which is usually wrong).
The reason is that split()
never splits to more fields than necessary. And the compiler interprets storing the results in ()
as not caring about the results, so split()
will not split the string at all, and thus return the full string, which gives a list of only one element in scalar context, hence the 1
.
You have two options to address this. First, you can override split()
's optimization by explicitly asking it to split into an unlimited number of fields:
my $count =()= split /:/, $string, -1;
Or else you can defeat the optimization by using another secret operator instead, the baby cart:
my $count = @{[ split /:/, $string ]};
This causes split()
to detect that its caller can store any number of fields, thus it will actually do the work before the anonymous array is thrown away after being used in scalar context.
Flaming X-Wing
=<>=~
Discovered by Philippe Bruhat, 2007.
This operator applies a regular expression to a single line of input and assigns the captured values to the expression to its left-hand side.
# pick named fields from input
@data{@fields} =<>=~ $regexp;
The above statement decomposes as follows: =~
provides scalar context to <>
on its left, thus matching on a single line of input. If the regular expression contains captures, having an array-like structure on the left side of the =
provides list context, and the captured data is assigned to the structure.
This operator is also a container. So the X-Wing can have a pilot!
# use the source, Luke!
$luke = \*DATA;
@data{@fields} =<$luke>=~ $regexp;
Kite
~~<>
Discovered by Philippe Bruhat, 2012. (Alternate nickname: "sperm")
This operator is actually a combination of the inchworm and the diamond operator. It provides scalar context to the readline()
builtin, thus returning a single line of input.
It's only useful in list context (since <>
already returns a single line of input in scalar and void contexts), for example for getting several lines at once:
@triplets = ( ~~<>, ~~<>, ~~<> ); # three sperms in a single egg?
Like the other operators based on bracketing constructs, the kite is a container, and can carry a payload (a file handle, in this case).
Note that when the filehandle is exhausted, the kite operator will return the empty string instead of undef
.
Mnemonic: It provides a feature that is tied to one line, a string, as it were. (Tye McQueen in http://www.perlmonks.org/?node_id=959906).
Ornate double-bladed sword
<<m=~m>>
m
;
Created by Abigail, 2003, for comp.lang.perl.misc.
This operator provides multi-line comments, by clever use of heredoc syntax and beautiful symmetry. Quoting <slrnb382jc.tfm.abigail@alexandra.abigail.nl>
:
<<m=~m>>
Use the secret operator on the previous line.
Put your comments here.
Lots and lots of comments.
You can even use blank lines.
Finish with a single
m
;
The "ornament" is the m
ribbon with the ;
throwing blade attached to it.
Note that the "commented" text is actually a double-quoted string in void context, which can have some side effects.
Screwdriver operators
Discovered by Dmitry Karasik, 2007, while looking for !
-based operators.
All screwdriver operators are conditional operators. Like screwdrivers, they come in 4 major types, with different handle lengths.
Flathead
-=!! -=!
This operator provides conditional decrement:
$x -=!! $y # $x-- if $y; $x -=! $y # $x-- unless $y;
Phillips
+=!! +=!
This operator provides conditional increment:
$x +=!! $y; # $x++ if $y; $x +=! $y; # $x++ unless $y;
Torx
*=!! *=!
This operator provides conditional reset to
0
:$x *=!! $y; # $x = 0 unless $y; $x *=! $y; # $x = 0 if $y;
The torx screwdriver operator does not work properly with negative numbers different from
-1
on Perl versions lower than or equal to 5.13.5.Pozidriv
x=!! x=!
This operator provides conditional reset to
''
:$x x=!! $y; # $x = '' unless $y; $x x=! $y; # $x = '' if $y;
(This one was discovered by Philippe Bruhat in 2009, while preparing a talk about the secret operators.)
Mnemonic: the screwdriver's head is the best mnemonic (-
and +
for increment and decrement, *
for the null number, x
for the null string).
Winking fat comma
,=>
Discovered by Abigail, 2010. (Alternate nickname: "grappling hook")
Visually looks like a fat comma, but without the left-hand side behaviour.
This operator is used to retain the documenting features of the fat comma, while disabling the string interpretation of the word to its left.
use constant APPLE => 1;
use constant CHERRY => 2;
use constant BANANA => 3;
%hash = (
APPLE ,=> "green",
CHERRY ,=> "red",
BANANA ,=> "yellow",
);
is equivalent to:
%hash = ( 1, "green", 2, "red", 3, "yellow" );
Mnemonic: the comma ,
is an off-switch for the fat comma's stringification.
Enterprise
( )x!!
Discovered by Aristotle on PerlMonks, 2006. (Alternate nicknames: "NCC-1701", "snail")
It is often necessary to conditionally include items in a list:
my @shopping_list = ('bread', 'milk');
push @shopping_list, 'apples' if $cupboard{apples} < 2;
push @shopping_list, 'bananas' if $cupboard{bananas} < 2;
push @shopping_list, 'cherries' if $cupboard{cherries} < 20;
push @shopping_list, 'tonic' if $cupboard{gin};
The Enterprise lets you build the list and add only the items that match the condition, in a single statement:
my @shopping_list = (
'bread',
'milk',
('apples' )x!! ( $cupboard{apples} < 2 ),
('bananas' )x!! ( $cupboard{bananas} < 2 ),
('cherries' )x!! ( $cupboard{cherries} < 20 ),
('tonic' )x!! $cupboard{gin},
);
This operator is a container, which means the Enterprise can have a large crew.
The Enterprise is simply a list repetition operator ()x
followed by a boolean (see the Bang Bang operator above) which will be interpreted as 1 or 0 in a numeric context.
Because of precedence issues, complex conditions on the tail of the Enterprise may need to be put between parentheses.
Key to the truth
0+!!
Discovered by Toby Inkster, 2013.
This operator is a combination of the Venus and bang bang operators. It simply makes the boolean false into the 0
numeric value.
my $true = 0+!! 'a string'; # now 1
my $false = 0+!! undef; # now 0
Abbott and Costello
||()
Discovered by Yves Orton.
This operator makes a false value disappear in list context. It simply replaces a false scalar by the empty list.
my @shopping_list = (
'bread',
'milk',
$this ||(),
$that ||(),
'apples'
);
Mnemonic: one is tall and one is fat, just like the famous comedy duo.
SECRET CONSTANTS
Space fleet
<=><=><=>
Discovered by Damian Conway.
Even though it looks like a sequence of three spaceship operators, only the middle ship is an actual spaceship. The two outer "spaceships" are actually calls to glob("=")
.
This constant has the value 0
.
Amphisbaena
<~>
Discovered by Rafaël Garcia-Suarez, 2009.
Under Unix, will be equal to the real user home directory (by using glob
). On Win32 it will expand to $ENV{HOME}
if it is set (which is quite uncommon) or return '~'
else.
AUTHOR
Philippe Bruhat (BooK)
ACKNOWLEDGMENTS
The author would like to thank José Castro, Andrew Savige, Dmitry Karasik, Abigail, Yitzchak Scott-Thoennes, Zefram, Tye McQueen, Maxim Vuets, Aristotle Pagaltzis, Toby Inkster, Ævar Arnfjörð Bjarmason, Rafaël Garcia-Suarez, Andreas J. König, Andy Armstrong, Pau Amma, Keith C. Ivey, Michael R. Wolf, Olivier Mengué, Yves Orton and the Fun With Perl mailing list for inspiration, suggestions and patches.
REFERENCES
As shown below, most of the secret operator action happens on the Fun With Perl mailing-list.
Around 1993, according to Randal Schwartz in his "My half-life with Perl" talk given on July 25, 2013 at OSCON:
Larry's daughter (Geneva?) named the <> operator for me (I named the <=>)
Post
<1994May1.035104.25990@netlabs.com>
incomp.lang.perl
Larry Wall discovers the baby cart and describes it as "a way to interpolate function results into a string".
Post
<slrnb382jc.tfm.abigail@alexandra.abigail.nl>
incomp.lang.perl.misc
Abigail coins the term "secret operator" to describe
<<m=~m>> m ;
.http://www.nntp.perl.org/group/perl.fwp/2005/02/msg3691.html
Original "secret operators" thread. Several of the detailed explanations in this manual page come from this thread.
http://www.nntp.perl.org/group/perl.fwp/2005/02/msg3708.html
Description of the space station operator.
http://www.nntp.perl.org/group/perl.fwp/2006/07/msg3855.html
Naming the baby cart operator.
http://www.nntp.perl.org/group/perl.fwp/2006/07/msg3891.html
Aristotle explains how the baby cart can be used to break aliasing.
http://www.nntp.perl.org/group/perl.fwp/2007/11/msg4006.html
Description of the flaming X-Wing secret operator.
http://www.nntp.perl.org/group/perl.fwp/2007/11/msg4028.html
Description of the screwdriver operators, and other
!
-based operators.http://www.nntp.perl.org/group/perl.golf/2009/06/msg2524.html
Description of the fourth screwdriver operator (Pozidriv).
http://www.perlmonks.com/?node_id=564792
Secret Perl Operators: the boolean list squash operator, x!!, by Aristotle Pagaltzis, describes the Enterprise operator.
http://www.nntp.perl.org/group/perl.fwp/2012/03/msg4169.html
Description of the sperm/kite operator.
http://www.nntp.perl.org/group/perl.fwp/2012/04/msg4192.html
Proposal for an alternate, family-friendly, nickname for the goatse operator, with a second order inside joke.
The key to the truth operator was described to me on 2013-09-28 by Toby Inkster on the
#moose
irc channel and private messages.
More secret operators didn't make it to this list, because they don't have a name yet.
http://www.nntp.perl.org/group/perl.fwp/2007/11/msg4028.html
The fwp post that presents the screwdriver operators also presents a few more
!
-based operators.
COPYRIGHT
Copyright 2010-2013 Philippe Bruhat (BooK).
LICENSE
This documentation is free; you can redistribute it and/or modify it under the same terms as Perl itself.