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 =:)

October 01, 2013, 12:48

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

Leave a new comment

(why do I need your e-mail?)

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

Type the first letter of your name: (just to make sure you're a human)

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

Advertisements