The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

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

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+ or +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 ~- and -~

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.

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;

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

    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

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é 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.

More secret operators didn't make it to this list, because they don't have a name yet.

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.