One of the questions we have asked potential recruits at The Perl Shop is, “What do you feel are weaknesses with Perl?” I feel it’s high time that I give my own answer to that question.
Almost seven years ago, I told my story about using a disciplined software-development approach to deliver a project for a hackathon. At the time, I was a Perl devotee, and I still believed in the Perl ecosystem. And part of that story was that Perl was a wonderful language to use for this project because it was so powerful. I started with Paul Graham’s story about developing the Viaweb code using Lisp:
Our hypothesis was that if we wrote our software in Lisp, we’d be able to get features done faster than our competitors, and also to do things in our software that they couldn’t do.
And then I placed Perl on the same pedestal:
Writing in a computer language must accomplish two things: (1) tell the computer how to solve the problem with which it’s being tasked, and (2) tell humans how the computer is solving the problem with which it’s being tasked. The first you can accomplish in Brainfuck. The second makes high-level development possible and requires a much more expressive language.
And that is what Perl was designed to do.
This may even have been true at one point. When I wrote those words, it was still true at the level of statements and philosophy. And maybe back then, Perl may even have still had a fighting chance.
Java was at version 7 and did not yet support lambdas or the Stream API. Python was at version 3.3 and had just added
yield from to delegate to a sub-generator. Event-driven concurrency (
And Perl was at version 5.16 and had been in decline for a small enough number of years that we could still fool ourselves that Perl wasn’t dying, just in repose, and we could still ignore the prophets that proclaimed otherwise. Yeah… Modern Perl had been published just a few years before. Moose was the most-advanced MOP in common use. PCRE still meant “Perl-compatible regular expressions,” but ours did extended regexes. And we invented CPAN! Don’t harsh my chill, dude! I’m busy reliving past stories of victory! And we were about to get postfix dereferencing, key/value slices, and (we thought) subroutine signatures. It didn’t hurt that all of the “Perl is dead” memes had the maturity of a seven-year-old or that we lived and worked in a cult-like echo chamber. (Take heed, Python programmers… but that’s another post.)
In reality, it took years to get Raku on a separate track. We still haven’t released Perl 7. But we finally have a promise of a built-in class system. And we still don’t have non-experimental subroutine signatures. All of this is due to politics and infighting within the Perl community.
Yes, I understand that the Perl core is a mass of legacy code and difficult to add new features to. I understand that backward compatibility is very important, and you don’t want to break 25-year-old legacy applications with a new Perl release. I understand that there are political disputes that make it difficult to decide to which variation of a feature to lend official imprimatur—or whether official imprimatur is even desirable within an ecosystem whose motto is (myth has it), “There’s more than one way to do it.” I understand how difficult it is to attract new blood when a top concern of Perl developers (including yours truly) is how to escape being pigeonholed as a Perl developer. But at the end of the day, what makes the difference is whether we could get the job done, and these are all little more than self-justifications for why it couldn’t get done. And that’s why this post is not primarily about any of those things.
So here is my answer to the question: “What do you feel are weaknesses with Perl?”
Lack of standard features
Part of the Perl philosophy is to make the easy things easy and the difficult things possible. This is not a weakness of Perl. To that end, when the core language has not kept up with industry-standard features, third parties have developed packages that provide those features.
Nowadays, in order to do serious Perl programming, you need more than just Perl. Rather, you need a suite of bolt-on extras, along with their concomitant boilerplate, just to bring your language up to feature parity.
I address a few of these specifically below.
No standard object system
In Perl, objects are just blessed data structures. That means you build your own object system, and there are dozens of them.
Moose is the defacto standard, and it plays well with the other major ones. But its syntax, while powerful, is often awkward and verbose. There’s really no way to create a class without at least several lines of boilerplate. Rumor has it that Ovid’s Corinna will be integrated into core for the 5.38 release, but frankly, we’ve heard analogous rumors before.
No standard exception handling
In Perl, exceptions are overloaded errors: you use
eval to catch
Unfortunately, there’s a list of edge conditions that you need to keep in mind, and most developers don’t remember them all (or don’t know about them all).
Or you can use an add-on package to do it for you. The most popular of these seems to be
Try::Tiny doesn’t work with
Future::AsyncAwait); for that, you need to use
Syntax::Keyword::Try. And the two have slightly different syntaxes and caveats.
No generators or coroutines
Perl handles lists well, but it has no way to lazy-evaluate a list.
There are packages like
Iterator::Simple that allow you to return values one by one, but no way to feed that through
grep without first generating all of the items in the list.
The closest thing to coroutines is
Coro, which is an asynchronous “cooperative threads” (aka “green threads”) add-on, but see below under “concurrency.”
No type safety
(And no, Moose’s type constraints are not the same thing: those are a completely different animal, which provides some runtime type safety but which don’t support static analysis of, e.g., method signatures.)
No standard import system
In Perl, each module is responsible for importing itself into other namespaces.
There are standard packages that aid in this mission, in particular the
Exporter package, which is part of the standard distribution. But hardly a project goes by where there’s not at least one developer who has a favored alternative, which is easier, simpler, more powerful, less verbose, etc… and which may or may not have strange interactions with how other modules import or export symbols. Fun times.
No feasible concurrency model
Perl got started in web development, and web development is still its greatest strength—such as it is.
But to do modern web development, you need to work in a distributed environment. You need to manage multiple outstanding requests to a network of services. In short, you need concurrency.
fork, the bare minimum. There are packages that build on
fork, but I haven’t seen one that comes close even to Python’s built-in
Perl’s threads are a half-implemented joke that is not taken seriously within the Perl community itself.
Event-driven programming relies on awkward, method-based paradigms.
POE was the standard for a long time and is quite heavyweight.
AnyEvent made events easier and standardized the paradigm significantly, but it’s still primitive compared to current industry patterns.
Coro is a green-threads implementation that dates back to the early 2000’s that brings us part-way to modern— But having worked on large web systems for the past 16 years, mostly in Perl, I’ve also never had occasion to use it, and that should tell you something about the Perl ecosystem.
await are bolted-on extras.
Future::AsyncAwait seems to be the most modern incarnation. It doesn’t work with the standard Perl profiler, and you need to use
Syntax::Keyword::Try if you want compatible try-catch—which is not the standard on most projects. Still IMO the best bet. (Use it with
AnyEvent::Future for full asynchronous development.)
Perl is good for CGI-style scripts (à la PSGI and Plack), but increasingly, the ecosystem doesn’t adequately support the needs of modern distributed development.
Poor IDE support
This is probably due to (a) it often being difficult to statically analyze Perl code and (b) limited (and diminishing) community resources available to implement IDE support.
Alexandr Evstigneev, single-handedly AFAICT, supports a JetBrains Perl plugin. I use it for my development. It can complete symbols for me, find usages, rename things, manage POD, reformat code, and so forth. Although these are excellent and needed features, they still pale in comparison to standard features available for other languages. It supports few refactorings and no code generation. There’s a remote-debug capability (which I need in order to debug), but I haven’t figured out how to get it to work. And the IDE often can’t figure out whether a symbol is defined, often due to the fact that the defining module uses some strange import system or implements some nonstandard syntax.
To be fair, Perl developers don’t seem to do much with IDE’s, anyhow. Some (many?) of them still prefer
(For a long time, I considered myself a forward-thinker, as I used a graphical text editor, instead of a terminal-based one. How convenient it was to point-and-click copy-and-paste and so forth, something that my colleagues couldn’t do.)
There are more
There are more items I could add to this list: other important features missing from the standard library, difficulty embedding Perl, GUI support, lack of third-party support.
I’m just stating for the record where Perl comes up short. A decade ago, this list was just as long but perhaps less serious, as everyone else was also chasing these things. At this point, everyone else has surpassed Perl. The rest of the industry seems to have left it in the dust. And I’m pessimistic about Perl’s chances going forward, even if things change drastically overnight—and I don’t expect them to.
One last reflection: I recently had the opportunity to work on a fairly complicated, production-quality Python project. I had very few complaints. (One was how primitive Python’s automated test framework is. Perl’s latest testing library leaves most others behind.) Overall, I was enthralled with how easy it was to get stuff done in Python. It was quite a pleasant experience and one I’m anxious to repeat.