Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
branch: master
Fetching contributors…

Cannot retrieve contributors at this time

654 lines (426 sloc) 20.312 kb

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 and assign captures
    ~~<>         Kite                        a single line of input
    <<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

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 (<>) and the spaceship operator (<=>). 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 explicitely documented.

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

There is a good reason this page is not listed in the main documentation page: 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. It also wouldn't be much of a secret if it was listed in the main manual page. ;-)

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"

This is a container, or circumfix operator. The expression inside the [] is run in list context, stored in an anonymous array, which is immediately dereferencedi by @{}.

You will see this occasionally in production code.

Bang bang !!

This operator was discovered even before Perl existed, by C programmers. 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 the late nineties.

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 $.;
    }

Inchworm ~~

This operator is basically a shorter scalar (shaves 4 characters!) using the same idea as the secret bang bang operator.

    $ perl -lEsay~~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 complement two architecture).

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 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 integers, they must be used under the scope of use integer, so that signed integers are used 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 complement two 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 spacestation 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 =( )=

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.

In this case, the proper secret operator to use is baby cart:

    my $count = @{[ split /:/, $string ]};

which forces split() to 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 ligne 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 scalare 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 filehandle, in this case).

Mnemonic: It provides a feature that is tied to one line, a string, as it were. (tye 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 multiline 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.

Screwdriver operators

Discovered by Dmitry Karasik, 2007, while looking for !-based operators.

All screwdriver operators are conditional operators. Like screwdrivers, they come in 4 majors 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;
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.

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

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 and the Fun With Perl mailing list.

REFERENCES

As will appear below, most of the secret operator action happens on the Fun With Perl mailing-list.

Post <1994May1.035104.25990@netlabs.com> in comp.lang.perl

Larry Wall discovers the babycart and describes it as "a way to interpolate function results into a string".

Post <slrnb382jc.tfm.abigail@alexandra.abigail.nl> in comp.lang.perl.misc

Abigail coins the term "secret operator" to describe <<=~>> 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 spacestation operator.

http://www.nntp.perl.org/group/perl.fwp/2006/07/msg3855.html

Naming the babycart operator.

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.nntp.perl.org/group/perl.fwp/2012/03/msg4169.html

Description of the sperm/kite operator.

More secret operators that 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 scredriver operators also presents a few more !-based operators.

http://www.perlmonks.com/?node_id=564792

Secret Perl Operators: the boolean list squash operator, x!!, by Aristotle Pagaltzis.

COPYRIGHT

Copyright 2010-2012 Philippe Bruhat (BooK).

This documentation is free; you can redistribute it and/or modify it under the same terms as Perl itself.

Jump to Line
Something went wrong with that request. Please try again.