The Weaknesses of Your Programming Language: a lament

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 (asyncio) was years away. JavaScript had strict mode, but ES6 was still years away. GoLang was at version 1.2 and was poised to take over the universe. Rust was about to release version 0.6. The latest PHP version was 5.4.13, and no one knew what was coming in a couple of years with 7.0— We all thought PHP was a bad joke, and back then, yeah, it still was.

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.

Meanwhile, Python, JavaScript, GoLang, Rust, Java—and yes, even PHP—have moved on to bigger and better things.

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

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. But Try::Tiny doesn’t work with async/await (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 map or 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

Perl is not a statically typed language, like Java or GoLang. So you might not expect “type safety” to be on my list. Perl is a dynamically typed language, like Python and JavaScript…

But both Python and JavaScript now support gradual typing, at least via external tools. Whenever I program in Python or JavaScript (or TypeScript), I include type declarations that at minimum help my IDE warn me when I accidentally pass the wrong parameter in the wrong place, even without running any code. There’s simply no parallel in the Perl world.

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

Perl has 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 subprocess library.

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.

Futures and async/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 vi.

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

Note that I’m not focusing on any of the third-grade gripes people make about Perl. I don’t think sigils are bad, and it’s as easy to write readable and maintainable Perl code as to do so in just about any other language. If you want executable line noise, look at Lisp or Haskell. There’s nothing wrong with the topic variable. Perl is not “too slow” any more than Python or Java is too slow: the only benchmark that matters is the application I’m actually developing. I’m not complaining about the Perl community being a bunch of old fogeys set in their ways and obstinately resistant to change. (And this is not as often true as you probably think it is. Otherwise, why would we all be learning Python and JavaScript and GoLang?)

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.

This entry was posted in Uncategorized and tagged , , . Bookmark the permalink.

Leave a reply