Hacker News new | past | comments | ask | show | jobs | submit login
The four noisy horsemen of Perl hate (phoenixtrap.com)
45 points by todsacerdoti 4 days ago | hide | past | favorite | 54 comments

I like the author's list. Very solid and some of the same arguments I try to use when people tell me they don't want to ever mess with Perl because it's unreadable.

I still haven't found another language as easy and fast to do text manipulation, parsing, calling out to the shell, regex, whatever. For scripting, Perl is awesome.

Recently I've been using Python instead, simply because I feel like I'm the last person in tech who likes Perl. This stuff is all doable in Python but I still miss my good ol' Perl.

My 2 biggest complaints with Python vs Perl are 1) regex's - the perl syntax is so much faster and easier, and 2) running other command line programs from the shell and reading their output. Perl makes both of those things absurdly quick and easy to do.

You're not the last, and I feel the same way. Perl is popular enough that there is enough documentation out there, stable enough that all that documentation is good, even if it's 20 years old, and niche enough that most of it is written by knowledgeable people.

With Python, I first have to ensure that the page I'm reading is no more than 2-3 years old, then the copy and paste requires me to re-fix the code, since the syntax is too brittle to stand up to whitespace changes.

I never got why this was such a huge deal for people to do. In vim it's super easy to just select a bunch of text you've pasted in, elimiate all the whitespace with some << commands, and then select what you need to be indented and >> it back into place. Takes like 5 minutes top even for larger amounts of text... beyond that, what are you even doing copying and pasting that much in?

That said I do like perl for many things python just isn't as elegant at and your comment about old documentation still staying fresh is pretty true

> With Python, I first have to ensure that the page I'm reading is no more than 2-3 years old, then the copy and paste requires me to re-fix the code, since the syntax is too brittle to stand up to whitespace changes.

I find that I also often have to re-fix the code because so many Python example writers present their examples as REPL sessions, with the code I want to actually copy littered with ">>>" prompts and the output from each individual line's execution.

I wrote Perl (badly) for a few years before moving to Ruby in the mid 2000s.

You can really see Perl's influence in Ruby when it comes to text manipulation, everything you need is likely in the standard library.

If you're not yet fully sold on Python, Ruby might be worth a try. It's like Perl's elegant, sensible cousin.

Ruby... thanks for the suggestion. I'll give it a try next time!

I spent some time in the late 90s struggling with picking up perl for ye olde cgi-bin. It was definitely harder to grok then most, I think if you come up from the shell at that time with a large familiarity with awk and sed it was easier to grok.

I think it quickly fell down when it became the way to do dynamic web applications for which it wasn’t really suited. As horrible as php was (then) from a language perspective it’s purpose built nature, made it way easier for early web uses. It did a good job of solving one problem and stayed in its lane.

It’s interesting that it seems, for the most part, that Ruby was mostly relegated to it’s use in Rails. It was probably one of the easiest and most intuitive languages I’ve picked up (I never got into python) and it quickly became my defacto scripting language though now I pretty much just use node since JavaScript is my day to day and I'm so familiar with the ecosystem.

Ruby is much closer to Perl than is Python.

My reason to not like Perl is that the language does not support function arguments explicitly. What? People wrote web apps in a language with bash-style argument handling. You have to shift your arguments off the @_ argv array. That, and my student job was maintaining ISP software written in the 90s in Perl by several generations of new programmers. It was very educational. :)

What you're describing is called subroutine signatures in Perl, an "experimental" feature I remember using on production in 2004.

At the time, I thought it made a lot of sense, after using other languages where this feature was standard and required.

However, I've since abandoned its use in Perl, because the traditional Perl way is much more flexible.

I do try to keep my `shift` statements towards the top of a sub, however.

    sub PaintHouse {
        my $house = shift;
        my $color = shift;

        if (!$house || !$color) {
            WriteLog('PaintHouse: warning: sanity check failed');
            return '';

        print "painting $house with $color paint";

        return 1;

I've never written Perl code, but I'm going to make a wild stab in the dark here and guess that the "flexibility" you're talking about involves putting the `shift` keyword half way down the function body, putting it inside `if` statements, putting it inside loops etc?

If so, that's not the kind of flexibility I ever want to see in a programming language.

No, the flexibility on offer is that you get regular arguments, optional arguments, variable numbers of arguments and keyword/named arguments all as a result of this mechanism.

I hardly ever use shift like this, preferring instead the more readable argument copying:

    sub PaintHouse {
        my ($house, $color) = @_;

I work in a legacy codebase (in PHP, not Perl) where the previous developer often wrote functions to be excessively flexible with regards to their parameters - many of the parameters are optional, some of them behave differently depending on whether they're passed as strings, integers or booleans, arrays can be passed as either flat or associative arrays, etc.

I'm sure he thought he was making his functions easier to reuse in different contexts but in practice the actual result is that it's impossible to modify any of those functions without considering _every possible_ combination of parameters that could be passed in. Often what should be a simple fix becomes something much more time consuming.

There is a place for flexibility in software design, but the parameter list of a function is not one of those places in my opinion.

I was inclined to do so on python and was reluctant to use a typed language.

I tried Go and Typescript and realized that the extra code is really, really worth the security, refactorability and safety.

I now frown on my beloved Python for being so permissive

    my $house = shift;
    my $color = shift;

    if (!$color) {
        $color = GetDefaultHouseColor();

That's one of my complaints too. But, you can use this kind of trick to get around it and make your code more readable:

   sub pretty_print {
    my ($filename, $text, $text_width) = @_;
Not as good as if it was just built into the language itself but better then the alternative.

Use experimental Perl feature:

  use Modern::Perl '2015';
  use feature qw(signatures);
  no warnings qw(experimental::signatures);
  sub foo($bar, $baz) { $bar+$baz }
  say foo(40, 2);
See `man feature` for details.

Or use CPAN modules: https://metacpan.org/pod/signatures , https://metacpan.org/pod/Function::Parameters

This is a unique and staggeringly awful aspect of Perl. What other mainstream language lacks function arguments?

Shell. You can approach Perl viewing it as an alternative to Python / Ruby / JavaScript, but that’s not the only way to look at it. Another is to look at it as a sh / sed / awk upgrade, and it absolutely excels in that. It’s easy to ‘shell out’, Perl adds more convenient data structures and keeps affordances to play well with other tools. It’s also very backwards-compatible, so if you want a small script for personal use that will not need you to do maintenance busywork — base Perl is the way to go.

The main one I use regularly with this 'feature' is a shell. I'd imagine it's where Perl got the idea from.

In reality, function arguments are an abstraction. You push your arguments onto a stack and read them off that stack. It's just that so many modern languages have that abstraction that we forget how it works underneath.

> What other mainstream language lacks function arguments?

Assembly language doesn't have function arguments. You just decide what to put in each register when you begin the function. So you can remember that eax is the count, ebx is the pointer to the buffer, or whatever. Or if you're a nice programmer you write a comment there.

Perl doesn't lack function arguments.

You can pass various arguments to a subroutine like you do in any other programming language and they can be acessed inside the function using the special array @_. Thus the first argument to the function is in $_[0], the second is in $_[1], and so on.

  # Function definition
  sub Average {
     # get total number of arguments passed.
     $n = scalar(@_);
     $sum = 0;
     foreach $item (@_) {
        $sum += $item;
     $average = $sum / $n;
     print "Average for the given numbers : $average\n";
  # Function call
  Average(10, 20, 30);
reference: https://www.tutorialspoint.com/perl/perl_subroutines.htm

A generic, obscurely named array that you can use to pass data into subroutines isn't what anyone ordinarily means by function arguments. The writer of a function should be able to specify multiple named formal arguments within the function signature. Again, this is a basic feature all other mainstream languages have.

It sounds like you are unfamiliar with this style, not that it "isn't what anyone ordinarily means".

Bash, Ruby, and Perl all support this style of argument passing.

Perl does not have named formal parameters, but instead supports passing arguments as lists / arrays. You can pass any number of arguments of any supported type this way.

If you've never programmed in a language that supports passing arguments in this manner, it will seem foreign.

However, argument passing in this manner has many benefits (eg easy to extend a function def, can easily add optional / req params with basic checking within subroutine) and after 15 min of doing it this way you don't really think about it again.

It sounds like a subset of Python where "def fun(*args)" is your only option for a function signature. And you have to do all the work of pulling apart *args to get the data you want, including manually throwing errors if you didn't get what you expected.

Python lets your function signature have required positional arguments, variable positional arguments (*args) AND variable keyword args (**kwargs). And everyone uses these features because it makes programming much more pleasant and manageable.

**kwargs is especially important for complex packages like sklearn or pandas, which have many functions with lots of options that often change with version. It would be utterly unimaginable to build these magnificent packages while chained to the underpowered, antiquated Perl style of argument passing.

> And you have to do all the work of pulling apart *args to get the data you want, including manually throwing errors if you didn't get what you expected.

Respectfully, isn't this just the same amount of work to define named function arguments?

In Perl you do the work of unpacking the array and then validating data. In Python you have the work of defining the function arguments and then validating the received data.

> Python lets your function signature have required positional arguments, variable positional arguments (*args) AND variable keyword args (*kwargs). And everyone uses these features because it makes programming much more pleasant and manageable.

Perl supports this as well. Same functionality as *kwargs is found by passing a hash to a subroutine. And of course *args is analogous to how Perl subroutines were designed to work.

You can use @_

Or you can use shift sequentially (my preferred style)

Or you can use traditional function signatures, which are behind a feature flag because of backwards compatibility.

The various shell languages (e.g. Bash) are probably the inspiration, although when Perl was written it was already pretty hard to justify.

Perl doesn’t lack function arguments, it’s just hidden behind a feature flag until the next annual release. A feature change had to be reverted to the more stable prior version but it’s de facto stable now.

Perl’s successor language, Raku, has sub arguments (even with lambdas) and optional type constraints.

Signatures are experimental, see[1]. Unfortunately, that means that it requires boilerplate.

[1] https://www.effectiveperlprogramming.com/2015/04/use-v5-20-s...

Compared to, say, Python, Perl requires a more conscious effort to write readable code, but in my experience it is a) possible and b) not that big of an effort. One can write equally unreadable gibberish in any language if one has the mind to do so (the International Obfuscated C Contest is an impressive, scary, and hilarious monument to this).

I don't write much Perl these days, I suppose the language will always have a spot in my heart, and whenever I need to quickly whip up a script that is too complicated for my puny shell-foo, I know where to turn to. :)

I think this is the real point about Perl code readability: it gives you enough flexibility to do things however you like, and as a result many programmers are faced with a mirror that reflects their own bad practices back at them.

People don’t hate Perl, they’re indifferent. I agree with what the author says, but it doesn’t matter. None of these reasons are significant when people today choose a language to build a new thing.

His quote at the end is ironic: “There are only two kinds of languages: the ones people complain about and the ones nobody uses.” I don’t hear people complain about Perl much. Mostly I see blogs about how people should use it more.

I'd like to avoid Perl at all costs.

I've used it professionally on and off most of my career. I hate it.

The line noise argument is still funny to me, and I've been a happy Perl developer for years. Recently I wanted to draw an irregular circle and bumped into this Stack Overflow answer that expressed the answer in some LaTeX dialect -- boy I found that hard to parse.


    \newcommand\irregularcircle[2]{% radius, irregularity
      \pgfextra {\pgfmathsetmacro\len{(#1)+rand*(#2)}}
      +(0:\len pt)
      \foreach \a in {10,20,...,350}{
        \pgfextra {\pgfmathsetmacro\len{(#1)+rand*(#2)}}
        -- +(\a:\len pt)
      } -- cycle

      \coordinate (c) at (0,0);
      \coordinate (d) at (1,2);
      \draw[blue,rounded corners=1mm] (c) \irregularcircle{1cm}{1mm};
      \draw[red,rounded corners=1mm] (d) \irregularcircle{1cm}{1mm};

Unfortunately I ran out of time and still have no idea what the final 3 lines of the irregularcircle command do, or why the \pgfmathsetmacro\len{} is repeated twice.

Source: https://tex.stackexchange.com/a/126179

I like Perl, but if the best argument for its readability is that it’s better than using an archaic macro-only typesetting DSL for graphics…

> still have no idea what the final 3 lines of irregularcircle do, or why the \pgfmathsetmacro\len{} is repeated twice.

Divide the circle in angles of 10 degrees. Each one will be a node for drawing the line. Then go to 10,20,30,40 degrees etc until reaching 350 degrees and assign a length for the radius in each node

This length will be is the desired radius of the circle plus a small amount of irregularity that is randomly assigned but starting at a value provided as second argument. Finally we need to close the circle with -- cycle. The polygon is defined as a -- b -- cycle, or in this case:

starting_node -- {iteration} -- closing_node. Iteration is a list of values for the radius each ten degrees.

If I'm not wrong, we need to use the macro two times because the first time we use a starting value with angle = 0 and then we iterate over the whole circle. We need to assure that we start and end exactly at the same radius value (the radius provided as first argument) so the polygon line will close correctly. Therefore the first and last node can't have any irregularity.

I created some big apps in mod_perl back in the day, and although I don't use it at all anymore, looking back I do appreciate the sigils.

Especially in the modern era of type safety and type inference, it can be hard to tell what variable "is" just by looking at its name or assignment. Whereas `%names` gives you a clue.

On reflection, my biggest critique of Perl is also its biggest strength: it's just so easy to use regular expressions. It's such an important language primitive, people use regex everywhere.

Unfortunately, even experts miss regex edge cases, and when regex fails, it can fail spectacularly. Then future-you (or worse, someone else) has to parse and fix that massive regex you wrote after drinking two espressos.

In general, clear beats clever. Even if it means your clear, lengthier solution is actually slower.

> Then future-you (or worse, someone else) has to parse and fix that massive regex you wrote after drinking two espressos.

There's things you can drink that are worse for clarity than espressos...

I cut my teeth on Perl back in the day, and while I have stopped using it completely by now, I am no hater. But this article does not contain the word "bless", and I wonder why it was left out. If I had to guess, it's not as easy to defend as the nice features.

> But this article does not contain the word "bless", and I wonder why it was left out.

Most people use Moose (or its variants) so they don't have to bless things anymore.

I think Perl not having OO built-in hurt it a lot when the trend towards OO started.

Of course Perl is more functional than OO so maybe it's time for a comeback now the pendulum has swung back...

Actually I think, it was killed by its strange standard library. A good base OO module in the standard, proper datetime modules, a good exception standard, proper iterators and the like, would have gone a long way to avoid the massive fragmentation which is CPAN nowadays.

Then another breaking factor was, I think, actually the long slow Apache 2 and mod_perl 2 migration back then, leaving Perl in one of the areas where it used to dominate in limbo for a long time as other alternatives like standalone appservers and the like simply were not very common initially, so there was no clear migration path. I still think, this was worse than the Perl 6 confusion.

In the end, we're now in some kind of downward spiral, where Python, Ruby, PHP have MASSIVE advantages in regards to the scope of their package repositories, while CPAN support of modern things, especially interfaces to Web APIs, is permanently half assed and unfinished.

The Perl elite spent too many years futzing over whether to include a MOP (meta object protocol) in the stdlib and, if so, which one. Clunky Catalyst, with its weird subroutine signatures, was also no match for Rails, PHP and Django.

You raise a lot of good points. I believe it is a combination of factors.

The list sums up most of the reasons I don't like Perl. It's not a bad language, I just find the syntax annoying and unnecessarily confusing.

That is a personal preference. I dislike the experience of working in Perl and will not work with it again if possible.

``` $addresses = [ { 'name' => 'John Doe', 'address' => '123 Any Street', 'city' => 'Anytown', 'state' => 'TX', }, { 'name' => 'Mary Smith', 'address' => '100 Other Avenue', 'city' => 'Whateverville', 'state' => 'PA', }, ]; ```

this already confused me. is the $ vigil for scalars? Why is address using it? Isn't address an array here?

Don't get it.

addresses is an array reference with two anonymous hash reference elements.

So if it's an array, why isn't it @addresses?

It's an array reference. If you replaced the [ ... ] with ( ... ) you'd have an array and use @. This is something I see people new to Perl struggle with, and I remember it taking me some time to grasp back in the day. It's pretty natural to me now, but I do feel it's something of a wart in the language.

References are scalars in Perl. @$ dereferences an array ref and %$ derefs a hash ref. You can also reference a scalar in Perl and deref it with $$ but I never understood why you would want to.

There was an article recently extolling the virtues of glue code. Perl was the duct tape of the internet for a long time. And, it deserves acknowledgement for that fact.

Lincoln Stein's CGI.pm was the default. More like sticky tape.

Okay, but if Perl wasn't going to implode it probably would have stopped collapsing before now. Honestly this feels like being told not to speak ill of the dead.

Applications are open for YC Winter 2022

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact