There is a mysterious underground Perl organization that hardly anyone has heard of. Their primary mission is to discover new secret Perl operators but they are not allowed to talk about them. I managed to infiltrate this organization and steal some of their secrets. Here are 8 secret Perl operators that I retrieved from their mysterious hoard:

(to be honest, only the first is a real Perl operator, all others are syntactic tricks.)

The Spaceship Operator <=>

<=> is the spaceship operator. Most commonly it's used to sort a list of numbers. Here is an example:

my @numbers = (-59, 99, 87, 1900, 42, 1, -999, 30000, 0);
my @sorted = sort { $a <=> $b } @numbers;
print "@sorted\n";

# output: -999 -59 0 1 42 87 99 1900 30000

If you don't specify a block with the spaceship operator to sort() function, it will treat the numbers as strings and sort them asciibetically:

my @numbers = (-59, 99, 87, 1900, 42, 1, -999, 30000, 0);
my @sorted = sort @numbers;
print "@sorted\n";

# output: -59 -999 0 1 1900 30000 42 87 99

In general the spaceship operator is defined as following:

  • $a <=> $b is -1 if $a < $b.
  • $a <=> $b is 0 if $a == $b.
  • $a <=> $b is 1 if $a > $b.
  • $a <=> $b is undef if $a and $b are NaN.

The Eskimo Greeting Operator }{

The Eskimo greeting operator can be most frequently met in Perl one-liners.

For example, this one-liner uses the Eskimo greeting to emulate `wc -l` command and prints the number of lines in a file:

perl -lne '}{ print $.' file

Here the Eskimo greets the print function. To understand what happens here, you have to know what the -n command line option does. It causes Perl to assume the following loop around your program:

while (<>) {
  ...
}

Where `...` contains the code specified by the -e command line option. If the code specified is `}{ ...` then it causes the while loop to be closed with no actions to be done and only the `...` part gets executed.

Therefore the one-liner above is equivalent to:

while (<>) {
}
{
print $.
}

This just prints the special variable $. which is the number of input lines processed.

This can be extended further and we can have Eskimo greet code on both sides:

perl -lne 'code1 }{ code2'

Code1 gets executed within the loop and code2 after the loop is done:

while (<>) {
  code1
}
{
  code2
}

If you are interested in the topic of Perl one-liners, see the first part of my article "Perl One-Liners Explained".

The Goatse Operator =()=

The Goatse operator, as nasty as it may sound, doesn't do any nasty things. Instead it does a wonderful thing and causes an expression on the right to be evaluated in array context.

Here is an example,

my $str = "5 foo 6 bar 7 baz";
my $count =()= $str =~ /\d/g;
print $count;

This program prints 3 - the number of digits in $str. How does it do it? Let's deparse the 2nd line:

(my $count = (() = ($str =~ /\d/g)));

What happens here is that the expression ($str =~ /\d/g) gets assigned to the empty list (). Assigning to a list forces the list context. The whole (() = ($str =~ /\d/g)) thing gets evaluated in list context, but then it gets assigned to a scalar which causes it to get evaluated again in scalar context. So what we have is a list assignment in scalar context. The key thing to remember is that a list assignment in scalar context returns the number of elements on the right-hand side of the list assignment. In this example the right-hand side of the list assignment is ($str =~ /\d/g). This matches globally (/g flag) and finds 3 digits in $str. Therefore the result is 3.

The Turtle Operator "@{[]}"

I couldn't find the name of this operator therefore I decided to name it the turtle operator, because it looks a bit like a turtle, @ being the head, and {[]} being the shell.

This operator is useful for interpolating an array inside a string.

Compare these two examples:

print "these people @{[get_names()]} get promoted"

and

print "these people ", join " ",get_names(), " get promoted"

Clearly, the first example wins for code clarity.

More precisely, writing

print "@{[something]}"

is exactly the same as writing

print join $", something

The Inchworm Operator ~~

The inchworm operator can be used to force scalar context.

Here is an example with localtime() function. In scalar context localtime() returns human readable time, but in list context it returns a 9-tuple with various date elements.

$ perl -le 'print ~~localtime'
Mon Nov 30 09:06:13 2009

Here localtime was evaluated in scalar context, even though it was called within print that forces list context. It returned human readable date and time.

$ perl -le 'print localtime'
579301010913330

Here localtime returned a list of 9 elements and print function just printed them one after another. To really see that it's a list of 9 elements, let's use the turtle operator:

$ perl -le 'print "@{[localtime]}"'
5 13 9 30 10 109 1 333 0

The Inchworm-On-A-Stick Operator ~-

For numbers greater than 0, this operator decrements them by one. Example:

my $x = 5;
print ~-$x;

# prints 4

It works because ~-$x parses to (~(-$x)), which on a two-complement machine is effectively the same as $x-1.

The Spacestation Operator -+-

The spacestation operator turns a string starting with positive number into a number. Here are some examples:

print -+-"4zy"   # prints 4
print -+-'3.99'  # prints 3.99
print -+-'2e5'   # prints 200000

The Venus Operator 0+

It's named the Venus operator because the astronomical symbol for the planet Venus looks similar.

It does the same as the spacestation operator, it numifies a string, but it binds less tightly than spacestation. An example:

print 0+"4zy"  # prints 4

Share the secrets!

Comments

balticman Permalink
November 30, 2009, 13:22

secret operators - its sounds very good :))

Chris Permalink
November 30, 2009, 14:17

3.99 is not an integer

November 30, 2009, 14:26

balticman, these really are secret operators!

Chris, thanks, fixed!

November 30, 2009, 15:15

Ah, the mystic secrets of Perl. Reminds me of the days when I was fortunate enough to do Perl as my day job. Since then alas the focus has been elsewhere, but weirdly enough I always liked that on the surface it's easy to work with, but you can go as deep as you want.

November 30, 2009, 16:00

Other proposed named for the turtle operator are "babycart" and "Supermarket Trolley" operator. See here:

http://www.mail-archive.com/fwp@perl.org/msg03595.html

Electric Bob Permalink
November 30, 2009, 17:04

What's "deparse"? Don't you mean... "parse"?

Irregardless, it sounds like overnegation to me. ;)

Tom Legrady Permalink
November 30, 2009, 17:08

The inchworm on a stick may do something, but since it duplicates a standard operator, pre-decrement, it isn't very useful.

Your choices are

$b = --$a;

Which is documented in the manual, so everyone should know what it means, and the cryptic and arcane

$b = ~-$a;

I suppose if you enjoy proving your superiority by doing things no one knows, you'll prefer the second. Personally, I prefer to not have my sleep interrupted at 3 am by someone wanting an explanation of weird code in a program that stopped working. There are enough useful and valid Perl idioms that beginners don't know, no need to add an unneccessary one.

April 19, 2012, 15:14

Actually, these are not the same.

--$a will decrement $a.

~-$a will decrement $a, but will not go negative.

Tom Legrady Permalink
November 30, 2009, 17:12

Oops, I typed two minus signs - - $ a but only one came out.

Tom Legrady Permalink
November 30, 2009, 17:16

The Eskimo greeting operator is cute, and it DOES save two characters over the standard

perl -lne'END{print $.}' file

November 30, 2009, 18:38

So Peter, you met with one of those mythical Perl monks and learn the ancient secrets of Perl. You are on your way to become a Perl Guru :D.

November 30, 2009, 19:13

~~ is now the smartmatch operator.

November 30, 2009, 19:38

A very useful post.

DanL Permalink
November 30, 2009, 21:01

It looks like the benefit of the inchworm-on-a-stick method is that it returns the value decremented, without actually decrementing the value:

my $a = 0;my $b = 2;$a = --$b;print "\$a : $a\n";print "\$b : $b\n";#-----$a = 0;$b = 2;$a = ~-$b;print "\$a : $a\n";print "\$b : $b\n";
returns:$a : 1$b : 1$a : 1$b : 2
November 30, 2009, 22:05

Hi,
I'm appalled at these "operators." These are not "operators" but rather anti-readable, anti-maintainable bits of syntax.

Your "eskimo" operator is visually syntactically invalid and is better off being forgotten. The readable form of

perl -ne '}{ print $. }'

ought to be

perl -ne 'END { print $. }'

which still uses a punctuation variable but that can be looked up directly in the perlvar manual page.

Your goatse is disgusting, both for bringing it up in conversation and for removing the appropriate white space. The perlop manual documents:

a list assignment in scalar context returns the number of elements produced by the expression on the right hand side of the assignment.

That is,

$count = () = ...

is an amalgam of the assignment

() = ...

which itself is a special case of

( $foo, $bar ) = ...

and the simpler

$count = ...

. This could plausibly be more readably written with spaces around the embedded empty list. I'm really ambivalent about suggesting even this because it's trading on a presumably less-well-known effect and a special case of syntax.

$count = () = ...

I would like to be upset with the turtle operator but I'm overwhelmed by the other flagrant violations of good sense nearby.

Inchworm operator

~~

is bankrupt for several reasons and should not appear in any person's code for several reasons. There is a perfectly readable operator

scalar

which does the right thing. "Inchworm" is two unary ~ bitwise negation operators. It casts the input first to string or integer (and breaks objects, floats, arrays, hashes, etc). For long strings, ~ asks for a negated copy. Perhaps that's expensive.

Separately, your ~(~(expr)) inchworm only even means what you intended in places where the parser expected an expression. In Perl 5.10 there is a separate smartmatch operator written as ~~ which is parsed in places expecting a binary operator.

print ~~$x; # inchworm
print $y ~~ $x; # smartmatch

"Inchworm on a stick" continues the abuse by invoking details of the representation of integers in memory. Are you for real?! Perhaps a more readable way to get the value of an integer minus one is:

$x - 1

.

"Space station" -+- is the three unary operators -, +, and -. I continue to be incredulous that you even posted this. I'm forced to guess a little at what's going on here. The first, inner - either negates the inner integer or adds a '-' character on the beginning of the string:

"-foo" eq -"foo"

.
The middle + is unused except as a fake to the parser to avoid writing the "--" operator:

+"-foo" eq "-foo"

. The outer '-' re-negates the inner value except that a string already starting with "-" turns into "+".

-"foo" eq "-foo"
-( -"foo" ) eq "+foo"
Eric TF Bat Permalink
November 30, 2009, 22:32

I couldn't figure out the inchworm-on-a-stick either (I learned Forth in my free time during university and got a High Distinction in Discrete Mathematics 1 because it enabled me to grok how stuff like two's complement arithmetic works). But the trick is that it's not the same as $x-- or --$x or $x-1: it's much weirder than that. Take a look at the output from this:

foreach my $x ((1,2,3,-1,-2,-3,0,1.5,2.5,3.1,4.9)) { 
    printf qq/%+2.2f %+25.2f\n/, $x, ~-$x;
}

+1.00                     +0.00
+2.00                     +1.00
+3.00                     +2.00
-1.00  +18446744073709551616.00
-2.00  +18446744073709551616.00
-3.00  +18446744073709551616.00
+0.00  +18446744073709551616.00
+1.50                     +0.00
+2.50                     +1.00
+3.10                     +2.00
+4.90                     +3.00

Very odd indeed, especially when you replace the second %...f with %d, and then you get this:

+1.00 +0
+2.00 +1
+3.00 +2
-1.00 -2
-2.00 -3
-3.00 -4
+0.00 -1
+1.50 +0
+2.50 +1
+3.10 +2
+4.90 +3

What I don't know is what good it would be. I mean, if $x is non-negative, then it's the same as int($x)-1, but the weird result for negative $x confuses me...

Rafi J Louis Permalink
April 11, 2014, 11:12

"What I don't know is what good it would be. I mean, if $x is non-negative, then it's the same as int($x)-1, but the weird result for negative $x confuses me..."

If something looks weird at sight, it will always have some weird use too.

Have you figured out what this number is or how it came? +18446744073709551616.00

Personally, i think these are good, not for corporate coding, 90% wont understand if you code like this. :D

Things like these are good for people who love to tear down every bit and do maximum exploitation of the language (in a constructive way).

Thank you.

kangu Permalink
December 01, 2009, 09:09

That was helpful thanks buddy!

December 01, 2009, 20:45

For people reading this article who see these tricks as harmful to readability and maintainability, these operators are great for saving strokes in code golf and also great for silly scripts and one-liners.

April 17, 2010, 22:23

fore!

Rafi J Louis Permalink
April 11, 2014, 11:22

One liners are very valuable, never under estimate.

In my company, a guy wrote a 15 line (approx) shell script. Code was readable, tidy.

Another guy wrote the code for the same funtionality having regex and pipes, looked so messy and unreadable. (2 pipes i think).

First guy's code took about 2 hours to run on about 80-100 files of size around 500 MB each.
Second guy's script completed the run in 4 minutes 20 seconds.

First guy was an average coder who used loops, conditions and some pipes. Second guy, omg, was a plumber... (you know what i mean :D ).

reza Permalink
December 04, 2009, 03:53

strictly speaking, many of them are not operators

Hans Permalink
December 09, 2009, 15:44

Thanks buddy! I'll show this to my colleagues who want to allow use of perl in production code. Your article shows why that is a bad idea.

December 09, 2009, 16:16

Bad code can be written in any language. Doesn't mean the language is unusable.

December 09, 2009, 16:22

Not that this stuff is necessarily "bad", btw.

Hans Permalink
December 09, 2009, 19:19

RB: are you kidding me? Every "operator" except for <=> is absolutely revolting. Of course you can write bad code in any language, but does perl actually incite this behavior?

bhedhen Permalink
December 10, 2009, 13:58

~-0 is so different than --0
@Eric TF Bat: the number is not weird. If you don't know it, try sqrt of it, the mysterious 4294967295 :>

dexter Permalink
December 15, 2009, 12:02

I use bang-bang operator:

$bool = !! 1;

It converts value to boolean. It is similar to venus operator:

$num = 0+ "42";

Raffaello Permalink
December 22, 2009, 16:20

I agree with RB. The fact that you can play around with the Perl syntax does not mean that you cannot write clean, elegant, readable code. It's like saying "The Internet is for perverts because there are Porn sites".

January 04, 2010, 17:36

This seems to be a rehash of Philippe Bruhat talk about secret operators, but it's presented as if it's all your work. You could have at least mention his name!

January 04, 2010, 20:40

GekkeHenkie, I haven't seen his presentation. But I'd like to see it. Can you email me it?

This post was written from a thread on Fun With Perl mailing list and several posts on Perl Monks.

Pushparaj Permalink
July 20, 2010, 14:31

Gud one ..where do i get more of these.....

January 01, 2011, 04:53

Ah, the mystic secrets of Perl. Reminds me of the days when I was fortunate enough to do Perl as my day job. Since then alas the focus has been elsewhere, but weirdly enough I always liked that on the surface it's easy to work with, but you can go as deep as you want.

Foo Bar Permalink
January 28, 2013, 23:28

Loved the names eskimo, turtle and venus. Never thought of 'em that way. Bookmarked =:)

January 16, 2014, 07:02

Your post is informative. I will bookmark it.

February 13, 2014, 08:42

Your information is very useful. Your post is very important to me.

no_name Permalink
March 01, 2014, 12:03

They are new operators to me except for <=> lol.

For ~~ operator example, I think 10 out of 10 people would use print scalar localtime; instead.

Cheers.

Dodger Permalink
May 14, 2014, 23:55

The syntax you're calling a "turtle" operator is actually pretty simple. It places the contents into an anonymous arrayref and then dereferences it into an array (which is thus interpolated into the quoted string, if used that way).

You can use it much like you use your "goatse operator" as well: $num_items = @{[qw(foo bar baz)]}.

But it's way more useful for something you didn't even mention: doing just about anything in the middle of double quoted strings.

For instance, call a function or method. Process a map against an array. Stuff like that.

It's especially useful in the middle of here-documents you don't want to break out of for formatting reasons like keeping a block of HTML looking clean.

For instance:
use CGI();
my $cgi = new CGI;
print <<"EOF";
<!doctype html>

<html><head><title>

Your arguments

<body><dl>

@{[map {<<"EOF2"} $cgi->param]}

<dt>

$_

<dd>

@{[$cgi->param($_)]}

EOF2

EOF

Dodger Permalink
May 14, 2014, 23:56

You apparently allow some HTML in your comments or something. My example got hosed and I'm not going to try to figure out what you're letting through and what you're breaking, and I'm not going to rewrite the whole thing with & lt ; entities so I hope you can figure out what was meant.

Fred Permalink
July 10, 2014, 16:43

evil spammers since May 23, 2014... :-(

September 20, 2014, 22:59

nice blog, thanks for sharing

September 20, 2014, 23:01

i like article, thanks for sharing

November 18, 2014, 11:54

excellent post, thanks for sharing such a great stuff. box office collection of pk | box office collection of pk.

November 26, 2014, 16:55

Thanks for taking the time to discuss this, I feel strongly about it and love learning more on this topic. If possible, as you gain expertise, would you mind updating your blog with more information? It is extremely helpful for me.

November 27, 2014, 12:18

thanks for sharing. Merry christmas songs | New year's.

jaavarsingh Permalink
December 05, 2014, 04:38

Hey this is really informative stuffs you have posted to this, add-on to this i have a table which i follow regularly:

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 ; 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
//() Leaning Abbott and Costello remove undef from list

Perl secret constants:

Constant Nickname Value
======================================================
<=><=><=> Space fleet 0
<~> Amphisbaena $ENV{HOME}

Thanks for the post and find usage of cloud billing and subscription management solution in your business which provides multiple benefits Click here to know more.

SHERYL Permalink
December 08, 2014, 08:49

Hey There. I found your blog using msn. This is an extremely well written article. I’ll be sure to bookmark it and return to read more of your useful info. Thanks for the post. I’ll definitely comeback.
Christmas wallpaper hd 2014 thank you

December 09, 2014, 14:51

I hope all Aamir fans will be waiting for releasing PK movie. Get all necessary information about PK movie music, release date and expected box office collection.

December 17, 2014, 07:52

well, this was a kind of new info for me. Thanks for sharing.
happy new year 2015
happy new year 2015 wishes
happy new year 2015 images
digg.

Leave a new comment

(why do I need your e-mail?)

(Your twitter name, if you have one. (I'm @pkrumins, btw.))

Type the word "computer_173": (just to make sure you're a human)

Please preview the comment before submitting to make sure it's OK.

Advertisements