What's wrong with Perl

By: Lars Marius Garshol
Italic comments by Sam Holden


Before we start

Just a note before you continue: this my personal experience of Perl. I know other people have other opinions of this language and they are welcome to them. I just want to present mine, because I see lots of messages on Usenet from people who seem to be about to learn Perl and I keep wanting to tell them that perhaps it's not a good idea. So, I wrote this article to get this off my chest once and for all.

I should perhaps explain why I refer to Perl as "the Camel": the Bible on all things Perl is Larry Walls "Programming Perl", which is published by O'Reilly in the Nutshell Handbook series. O'Reilly puts a nice 19th century engraving of an animal on the cover of each of these books. "Programming Perl" got a camel and has been known as "the camel book" ever since. Larry Wall also often refers to Perl as the camel.

Getting to know the Camel

I learned Perl 5 in early '97. I downloaded Patrick M. Ryans excellent introduction to Perl and found that a lot of the things I'd been doing the hard way with C, Pascal and Java were much much easier in Perl. For text processing and access to system functions Perl looked like a real God-send. Great, I thought, and bought myself "Learning Perl", by Randal Schwartz. (Also known as the "llama book".)

I read it pretty quickly and sucked up all these wonderful new features. The first program I made read a web server log and counted the number of times each page had been accessed. I wrote it in half an hour and it worked immediately! Not only did it work, but Perl also seemed to be able to overlook unimportant errors instead of crashing or aborting like C/Pascal/Java programs would.

(That program is now in version 1.54, and has quite a few users. So Perl isn't useless, just inconvenient.)

Getting to dislike the Camel

I was really enchanted with this language and started using it more and more. However, as I kept using it I kept discovering new things I didn't like. After a while it added up to a pretty sizeable list.

Illegible syntax

Though I'll admit readability suffers slightly...

--Larry Wall in <2969@jato.Jpl.Nasa.Gov>

One of the first things I discovered I didn't like was the syntax. It's very complex and there are lots of operators and special syntaxes. This means that you get short, but complex code with many syntax errors that take some time to sort out.

It also means that reading someone elses code is difficult. You can't easily understand someone elses scripts and adapt them to your own needs, nor can you easily take over the maintainance of someone elses program.

I write pretty clean Perl code, because I stay away from most of the obfuscating features, but even so it gets pretty hard to read. This is one ordinary example:

foreach $Key (@SearchEngines) {
    if (fields[11] =~ /$Key/i) {
	  $HitFrom[4]++;           #Yes, search engine

You could remove the nested hashes of course :

foreach $Key (@SearchEngines)
	if ($fields[11] =~ /$Key/i)
		my $referal = $SENames{$Key};

It's not even a particularly bad example. Here's a function from the Perl distribution that produces a Soundex value from a name or word:

sub soundex
  local (@s, $f, $fc, $_) = @_;

  push @s, '' unless @s;	# handle no args as a single empty string

  foreach (@s)

    if ($_ eq '')
      $_ = $soundex_nocode;
      ($f) = /^(.)/;
      ($fc) = /^(.)/;
      $_ = $f . $_ . '000';

  wantarray ? @s : shift @s;

It's a function you don't need to understand it... you just call it... if you want a more readable version, then either learn how to read a perl regular expression, or change the code to use functions...

However, even this isn't really bad. The Perl Journal has conducted an Obfuscated Perl contest. The winners are here . Be warned, though. These programs gives the word unreadable entirely new and previously unimagined meanings.

Bad documentation

The documentation for Perl itself as well as the libraries is:

This means that while the function you want may very well exist you may not find it, and if you do find it you may not be able to figure out how it works or that it really is the function you want.

The reason this is so is probably because the Perl libraries are very similar to the standard Unix ones, so the documenation sort of assumes you already know the Unix libraries. This is helpful for those who already know them and maddening for those who don't.

Some of the perl functions are simply system calls and they often refer to the system documentation - usually when it might vary on different platforms. The vast majority of functions and module are well documented... I mean the format of sprintf is explained as opposed to 'assumed'.

Let's say you want to turn of output buffering in Perl, maybe because you want to write a CGI script and have the results appear in the browser as they are produced. So how do you do that in Perl? Well, it's a bit difficult to know where to start.

You may look at the index of "Learning Perl" for buffering, but it's not listed. You can try to look through the manual pages for one on input/output. Ah! There is one, listed as "perlapio: Perl internal IO abstraction interface". That's the wrong one, unfortunately, it just lists the internal Perl C headers for the IO libraries. Wait! Maybe "Learning Perl" has a chapter on I/O? Chapter 6 is called Basic I/O, but has nothing on buffering. None of the later chapters cover this.

So what do you do? You look at the Perl reference card, under special variables, section 24. One of the last entries is: "$| If set to nonzero, forces a flush after every write or print on the currently selected output channel. Default is 0. See the manual for details."

I would look at the documentation that is meant to be so bad and type :

perldoc -q buffering | pod2html
Which sadly gives me :
No documentation for perl FAQ keyword `buffering' found
So I would then chop the extension off the word and try :
perldoc -q buffer | pod2html
Which gives me :

Found in /usr/local/lib/perl5/5.00501/pod/perlfaq5.pod

How do I flush/unbuffer an output filehandle? Why must I do this?

The C standard I/O library (stdio) normally buffers characters sent to devices. This is done for efficiency reasons, so that there isn't a system call for each byte. Any time you use print() or write() in Perl, you go though this buffering. syswrite() circumvents stdio and buffering.

In most stdio implementations, the type of output buffering and the size of the buffer varies according to the type of device. Disk files are block buffered, often with a buffer size of more than 2k. Pipes and sockets are often buffered with a buffer size between 1/2 and 2k. Serial devices (e.g. modems, terminals) are normally line-buffered, and stdio sends the entire line when it gets the newline.

Perl does not support truly unbuffered output (except insofar as you can syswrite(OUT, $char, 1)). What it does instead support is ``command buffering'', in which a physical write is performed after every output command. This isn't as hard on your system as unbuffering, but does get the output where you want it when you want it.

If you expect characters to get to your device when you print them there, you'll want to autoflush its handle. Use select() and the $| variable to control autoflushing (see perlvar/$ and perlfunc):

    $old_fh = select(OUTPUT_HANDLE);
    $| = 1;

Or using the traditional idiom:

    select((select(OUTPUT_HANDLE), $| = 1)[0]);

Or if don't mind slowly loading several thousand lines of module code just because you're afraid of the $| variable:

    use FileHandle;
    open(DEV, "+</dev/tty");      # ceci n'est pas une pipe

or the newer IO::* modules:

    use IO::Handle;
    open(DEV, ">/dev/printer");   # but is this?

or even this:

    use IO::Socket;               # this one is kinda a pipe?
    $sock = IO::Socket::INET->new(PeerAddr => 'www.perl.com',
                                  PeerPort => 'http(80)',
                                  Proto    => 'tcp');
    die "$!" unless $sock;

    print $sock "GET / HTTP/1.0" . "\015\012" x 2;
    $document = join('', <$sock>);
    print "DOC IS: $document\n";

Note the bizarrely hardcoded carriage return and newline in their octal equivalents. This is the ONLY way (currently) to assure a proper flush on all platforms, including Macintosh. That the way things work in network programming: you really should specify the exact bit pattern on the network line terminator. In practice, "\n\n" often works, but this is not portable.

See perlfaq9 for other examples of fetching URLs over the web.

In other words: to turn off output buffering in Perl, write


Pretty obvious, eh?

or any of the above methods from the so called terse documentation

Too many special constructs

Many of Perls features are built right into the language core itself, instead of being placed in separate libraries. One example of this is the handling of regular expressions, for which there is a special syntax. This has the advantage that there are some convenient ways of doing the things that are done most often, but it also means that you don't get the advantages of objects.

In other words, you can't precompile a bunch of regular expressions and stick them in a list. You can't return a regular expression from a file or set a variable to a regular expression.

However, this isn't unique for regular expressions. Perl also has a special construct called formats, which are a sort of templates you can use to generate nice textual reports. Quite handy, but built into the language. So, again, you can't create a list of formats, return them from functions etc.

I think you can do these things with file handles, but since they are also handled as special cases I've never been able to figure out how. I tried using references, but never made it work.

You can do them with GLOBS in fact, or you can use a module which wraps the said construct in an object... not too hard really...

Hard to build data structures

In the Perl documentation there is a separate manual page for how to create arrays within arrays and hashes within hashes. And it's really necessary. I had a lot of pain trying to figure out how to do this, even after reading it several times. This is something that really shook me, because in other languages this is something you just do, without thinking about it.

In Lisp, this sets the variable a to a list:

(setq a '(1 2 3 4)

Here we create list b where the first element is another list:

(setq b '((0.8 0.9 1) 2 3 4))

Here's the first list in Perl:


and here's the second:


(The @s before the variable names tells Perl that these are array variables.) That wasn't so bad, was it? Well, let's try to use this.

To pick out the first element of the first list in Lisp, you just write

(first a)

and Lisp gives you


To get the first element of the second list you write

(first b)

and Lisp gives you

(0.8 0.9 1)

Let's try this in Perl.


gives us


The $ before the variable name tells Perl that we want a single value (scalar in Perl lingo), not an array. The [0] tells Perl that we want the first value of the array. Perl, like many other languages and APIs counts from 0.

Then we do


and Perl happily gives us


That's right, Perl has broken into the list inside the b list and retrieved the first value of it. Or, rather, it flattened b into one list when we created it, so it's now really one consecutive list with 6 elements.

So Perl defaults to flattening out the lists into one list exactly the way Lisp does with 'cons' - which I think you would have to admit is the real primitive lisp list constructor, and it performs the same way the perl code above does...

To do this right we should have written


when we created the list. The []s enter a reference to the inner list as the first element of the outer list instead of flattening the inner list into the outer one.

Since the less common thing is is a little harder to do... standard huffman encoding I believe...

OK. So we try again:


gives us


So obviously we manage to find the array, but something still goes wrong along the way. The problem is that we use $b, which makes Perl think that we want a scalar and so it gives us a reference to the array instead of the array itself (which is not a scalar).

Aha! Of course! We must use


because @ tells Perl we want an array value. Not so. We get


once again. I've never managed to understand why this is so and at this point I gave up on the entire thing.

Others would read the man page and find out that that is an array slice and so will return the first element of the array as an array...

Some weeks later I saw a helpful posting on no.perl: one should request a reference to the array, like this


which actually gives us

(0.8 0.9 1)

So now I can write code with arrays inside arrays and hashes inside hashes.

Now, ask yourself: do you really think you should have to go through all this in order to put one list inside another?

I guess some people don't have any problems with reading a man page once, and finding on the first page of the perllol man page :

              @LoL = (
                     [ "fred", "barney" ],
                     [ "george", "jane", "elroy" ],
                     [ "homer", "marge", "bart" ],
Oh look an example of how to make a list of lists....

Discovering the Python

Programming languages teach you not to want what they cannot provide. You have to think in a language to write programs in it, and it's hard to want something you can't describe. When I first started programming - in BASIC - I didn't miss recursion, because I didn't know there was such a thing. I thought in BASIC. I could only conceive iterative algorithms, so why should I miss recursion?

--Paul Graham, ANSI Common Lisp.

NOTE: Below this point I wrote a lot of stuff about how easily I did various programs. Don't think that this is because I'm a great programmer, because I'm not. I can't even figure out how to write good Perl programs or how to return a file handle from a function in Perl. The reason why these projects were so simple for me is due to one thing: Python.

So, after discovering all these bad things about Perl, what did I do? I kept using it. After all, as bad as it was, it was still better than doing text processing and web programming with C, Pascal or Java, and there were no better alternatives.

Or so I thought. At the University bookstore there was this book called "Internet Programming with Python". Being both a language freak and an internet freak I thought this was interesting and picked it up. Somewhere in the beginning of the book there was an anecdote about a Python programmer who wrote all his Python programs so that when an error ocurred (ie: when an exception was thrown) the error handler called his beeper.

Wow, I thought. This sounds interesting. So I went home, found the Python tutorial, printed it out and started playing with Python. That night I wrote a POP3 client library in Python. Just like that. After going to bed I had an idea: wouldn't it be a lot nicer if I cached the messages and made this invisible to the user? In the morning I added that in half an hour.

I've since used this library to delete email without downloading it or moving 150 emails from one POP account to another. (Yes, I made a small SMTP library as well.) I can even use it as an email client using the Python interpreter as a command line.

I kept using Python more and more after this. I wrote a link checker that went over my web pages checking them for errors and kept adding more protocols and features to it. After a while I thought: this program spends a lot of time waiting for server responses. Maybe I can speed it up by using multi-threading so that it can wait for several servers at the same time?

I'd never really used multithreading before, but knew the theory behind it. I added this to the link checker in an hour and that includes the digging in the library documentation and removing the few bugs I did introduce. (Multithreading is much more complex than it sounds at first because things happen simultaneously. That's not Python's fault, though.)

Falling in love with the Python

The standard libraries

Did it stop there? It certainly didn't. Since then I've discovered these things in the Python libraries:

And these are things that come with the standard Python distribution! Not only do you get these things delivered with the interpreter, complete with documentation, they are also extremely simple to use and provide exactly the sort of things you want. Say you're writing a web robot and the robot has the URL to the current page in a string (cur_url) and a relative URL from this page to the next page in another (next_url) and you want to compute the absolute URL of the next page. This is the code:


Python also supports GUI programming via Tk on Win32, Mac and Unix. It's really easy to install, but not too well documented. There are also at least 3 other ways to do GUI programming with Python.

Perl also supports GUI programming via Tk, GTK, xforms, X11, libsx, Qt, and probably some others...

The SIGs

Python may become as big as Perl or Tcl. It is more "lovable" that those -- though perhaps also more controversial. It has an extremely supportive user community, and that is what will make it big.

--Guido van Rossum, creator of Python

When they want to create new libraries or "standards", the Pythoners form Special Interest Groups of volunteers, which anyone can join. Some of the results of this have so far been a common API for database modules (which means you can use the Sybase module and then exchange it with the Oracle one and only change 2 lines of code), an IDL-to-Python mapping for CORBA, a common text format for documentation strings and common tools and APIs for XML parsing are under development.

Python software

But, if this language really is so great, shouldn't people have written some pretty nifty software in it? Well, they have. Here are some examples:

Personally, my current project in Python is a fully validating XML parser .

Is it really any better than Perl?

I've included this section in case you want to know how Python handles the things I complained about in Perl.


Python is the most readable language I've ever programmed in. It took me half an hour to understand Medusa (even though it's pretty wierd in concept) and another half-hour to change it so that I could map URL paths in the web server to Python functions. An hour after that I could read my Gnus mail boxes through the web server. Another hour, and I could read news through it.

Here's my own implementation of the soundex function, written in November '97, when I was still new at this:

# no_tbl is an array I've constructed that maps characters to numbers
# is_letter is written by me, but I've since discovered that Python
# has it

def soundex(string):
    """Returns the Soundex code of the string. Characters not A-Z skipped."""

    if not is_letter(string[0]): string=string[1:]
    res =upper(string[0]) # This is where the result will end up

    for char in string[1:]:
	if is_letter(char):
	    if (new!="0" and new!=last):

    if len(res)<4:
	return res+"0"*(4-len(res))
	return res[:4]

perl version :

sub soundex
	my $string = lc(shift);

	$string =~ s/^[^a-z]//; # remove first character if not letter
	my $last = $no_tbl[ord(substr($string,0,1)-97];
	my $res = uc(substr($string,0,1));
	my $char;
	for $char (split //, $string)
		if ($char=~/[a-z]/)
			my $new = $no_tbl[ord($char)-97];
			$res.=$new if ($new ne "0" and $new ne $last);
			$last = $new;

	if (length($res)<4)
		return $res."0"x(4 - length($res));
		return substr($res,0,4);
I can't test it as I can't be bothered and I don't have the no_tbl list, and the pythn doesn't work without mystical import statement I guess, since when I try I get an error on lower(string)...

Anyway... a line by line conversion to perl...

The hard bit with perl is that perl does no treat strings as arrays - the way it should be done... strings are not arrays of characters... that is an implementation of strings...


There is a Python program that generates javadoc-like documentation from the documentation strings in Python programs. It can produce output in HTML, plain text and FrameMaker format.

Just like perldoc does for perl...

As for the standard library documentation, you can see for yourself .

Well I can't really as 'man python' doesn't tell me much except :

     Python Tutorial
     Python Library Reference
     Python Reference Manual
But where are they - it doesn't say.... and I'm in a text editor not a web browser right now...

Turning off output buffering isn't blindingly obvious, but not too difficult, either. You pretty quickly learn that sys.stdout, sys.stdin and sys.stderr are file objects that represent standard out, standard in and standard error. So, since stdout is an ordinary file object, it should behave as one with respect to output buffering as well. And it does. You can't turn off buffering, but you can flush data with the flush method:


What a shame in perl as I mentioned above you can try any of $fh->autoflush() or $fh->autoflush(1) or $fh->autoflush as they all work...


Python has very few built-in features compared to Perl. Regular expressions come in a separate module and are implemented as objects. Here's a list of compiled regular expressions:


It is easy enough in perl to write an object wrapper around a built-in so that you can do things like the above with it. In the case of regular expressions you can do it very simply with run time subroutines...

Files are also objects, as are Python modules and most other things. This means that you can pass them as parameters, stuff them in lists, subclass them and even create classes with the same methods and use them where code expects to see a file object or a module.

Of course perl is sort of pre OO... as in you didn't have to be OO to make it when perl first came to be. When OO took over, well of course perl has an OO syntax as well - an advatnage of all the dropping sin front of variables... So perl too has modules for most things...

Data structures

This is the two list examples in Python, (=> shows what the results are):

a[0]                  => 1
b[0]                  => [0.8,0.9,1]

Of course perl can't do that.. perl has some typing concepts that python doesn't. Namely that a scalar and a list are two different things and if you want to treat a scalar as a list then you have to add some droppings to the front - again huffman encoding...

In effect perl is like most spoken languages, there are plurals and singulars, and context often determines which is which...

Python also has hash tables, tuples (fixed-length lists) and full object-orientation.

perl has has tables... no tuples (though an object could do it) ... and full object-orientation.

Parting shot

What other people think

I'm not the only one who has opinions on this, so I'm including some links to other opinions here:

A final warning

Camels are docile when properly trained and handled but, especially in the rutting season, are liable to fits of rage. They spit when annoyed and can bite and kick dangerously.

--Encyclopedia Britannica.

If after all this, you still want to use Perl, then be my guest and go right ahead. I'm not going to stop you. You have been warned, though.

However, you may perhaps be curious about what the Encyclopedia Britannica has to say about Pythons? Here it is:

...the Monty Python Flying Circus troupe, which set a standard during the 1970s for its quirky parodies and wacky humour on television and later in films.

--Encyclopedia Britannica

That's right. Python was named after a comedy group, not after a nasty reptile. This is why there are so many wierd names and examples in the Python tutorials and source code. :-)



Thanks to:

Lars Marius Garshol , larsga@ifi.uio.no