Why Perl is not my favourite programming language

Ahem.

Remember the following important rule: There is no rule that relates the behavior of an expression in list context to its behavior in scalar context, or vice versa. It might do two totally different things. Each operator and function decides which sort of value it would be most appropriate to return in scalar context. Some operators return the length of the list that would have been returned in list context. Some operators return the first value in the list. Some operators return the last value in the list. Some operators return a count of successful operations.

In general, they do what you want, unless you want consistency.

– Larry Wall, the Perl functions manual page, perlfunc

Case closed.

About these ads

35 responses to “Why Perl is not my favourite programming language

  1. Michael Kohne

    I’ll have to give you that one…

  2. Aah! Now I see where you’re going. Well, I look forward to more postings about this sort of thing for more languages. Maybe commenters should join in the fun, and mention one thing they like least in Perl? I’d jump in, but I’ve managed to avoid programming in Perl.

  3. Equality Operators

    Binary ”==” returns true if the left argument is numerically equal to the right argument.
    Binary “eq” returns true if the left argument is stringwise equal to the right argument.

    So is “foo” numerically equal to “bar”? Wrong, try again.

  4. That’s the problem with the Swiss Army Knife. It’s perfectly possible to use it as a bottle opener, then slice your thumb off in the process. Bah.

    It’s a long time since I programmed seriously in Perl (mostly because writing OO Perl was just hideous). Right now Ruby seems to be just that little bit more elegant and sensibly thought out for my liking.

    But perhaps that’s just me.

  5. This is a silly complaint. What should sort return in scalar context? What should map return in scalar context? What should split return in scalar context? What should a global regex match return in scalar context?

    If you can find a unifying principle so that each of those operations returns the same thing in scalar context, you are the Buddha of programming language design.

    (And CodeMonkeySteve, ‘foo’ and ‘bar’ do numify to the same value, though pay attention to Perl’s warnings when you try that.)

  6. Chromatic, here is an example of when Perl’s do-the-right-thing rules go horribly wrong. This was brought to me attention by Stephen Sykes, by the way, who we’ll be hearing more from.

    my $foo;
    $foo = reverse reverse 'hello';
    print $foo;

    This prints out olleh, even though you would think that calling reverse twice would return the original word. However, if you read the API spec for reverse, you will see that it returns a list when called in list context. So the second reverse is operating in list context, just reversing a one element list and returning it. The left most reverse then reverses this “hello” in scalar context, since it is being assigned to a scalar, $foo.

  7. “Chromatic, here is an example of when Perl’s do-the-right-thing rules go horribly wrong.”

    As Larry says, it does what I’d want it to do. I guess, beauty is in the eye of the beholder.

    Phillip.

  8. Phil, are you sure that this is what you’d want it to do?

    $ perl -e 'print reverse "hello"'
    hello
    $ perl -e 'print reverse reverse "hello"'
    hello
    $ perl -e '$x = reverse "hello"; print $x'
    olleh
    $ perl -e '$x = reverse reverse "hello"; print $x'
    olleh
    $

    (Newlines inserted for clarity.)

    My guess is, that’s not even what Larry wants it to do.

  9. I’m no fan of the list/scalar overloading of reverse, but you must understand context if you are to understand Perl. List context fairly jumps out from those examples for good reason: the rules for which expressions apply which type of context are consistent.

  10. “you must understand context if you are to understand Perl”. That doesn’t sound like a point in Perl’s favour.

    In every other language, the types of expressions are determined by the expressions themselves, and that type percolates outwards into the containing expression. In Perl alone, the type of the subexpression is determined by the context is which it appears. Sorry, but that is just wrongheaded.

    (BTW., Perl was my language of choice for a whole decade; I am not a h8tr, I am disillusioned former lover who can’t continue to overlook the wrinkles and cellulite.)

  11. Aaron Davies

    my favorite gotcha in perl is non-composable expressions–i don’t have anything to hand, but last time i seriously worked in perl, i occasionally found operations that *required* an intermediate variable in order to work–you couldn’t just stick that variable’s assignment expression in parens and substitute it for the variable name. it tended to involve silly things like calling functions stored in hashes, but still, that sort of composability is one of the most basic things i expect from a language.

  12. Aaron, I find it hard to believe there are expressions that require an immediate variable like that. True, you may not able to substitute the RHS of the assignment directly, but that again has to do with context. Nothing a scalar() cannot fix.

  13. That’s horrible. How could a language have so different behaviour for calling

    print reverse reverse “hello”

    Mike Taylor, I might not understand the context of your examples, could you please tell us when would you actually want to call reverse twice?

  14. “Could you please tell us when would you actually want to call reverse twice?”

    When you are trying to understand how a language works. Here is the equivalent code in Ruby, a language that many, including Steve Yegge, feel is applicable in the same problem space as Perl, and which is therefore now a direct competitor for it:

    $ ruby -e 'p "hello"'
    hello
    $ ruby -e 'p "hello".reverse'
    olleh
    $ ruby -e 'p "hello".reverse.reverse'
    hello
    $ ruby -e 'x = "hello"; p x'
    hello
    $ ruby -e 'x = "hello".reverse; p x'
    olleh
    $ ruby -e 'x = "hello".reverse.reverse; p x'
    hello
    $ ruby -e 'p [1, 4, 9].reverse'
    [9, 4, 1]
    $ ruby -e 'p [1, 4, 9].reverse.reverse'
    [1, 4, 9]

    What’s going on here? The obvious thing: the semantics of Ruby’s reverse method are determined by the type of the object that it is invoked on — a string in all of the first six examples and a list in the last two. It’s very simple. Doesn’t it seem obvious that this is how it should work?

  15. Abigail: Aaron is probably talking about operators like keys(), values() and each() (as he mentions hashes) which in Perl only take a Hash not a list like keys/values/each returns. Thus this in Ruby:


    $ ruby -e ‘puts ({ “a” => “b”, “c” => “b” }).invert.keys’
    b

    Becomes this in Perl:


    $ perl -E ‘say keys %{ { reverse %{ { a => “b”, c => “b” } } } }’
    b

    I.e. for each step you need to construct an anonymous hash, dereference it and then pass it to the next function.

    Of course nobody would ever actually do this in Perl, you’d just construct an intermediate value:


    $ perl -E ‘my %hash = ( a => “b”, c => “b”); my %rhash = values %hash; say keys %rhash’
    b

    Or just use List::MoreUtils’s uniq() function:


    $ perl -MList::MoreUtils=uniq -E ‘my %hash = ( a => “b”, c => “b”); say uniq(values %hash)’
    b

    Mike: Since you mention Yegge you might appreciate another one of his quotes (from http://steve-yegge.blogspot.com/2006_10_01_archive.html):

    “As I’ve done for a great many other programming languages, I’ve bashed on Perl’s technical weaknesses at length in the past. To my continued amazement, the Perl folks are the only ones who never get upset. They just say “Haha, yeah, boy, you’re right, it sure is ugly. Heh. Yeah, so, um, anyway, I’m going to get back to work now…” It’s awesome. I’ve gained so much respect for them. It’s almost enough to make me go back to programming in Perl.”

    We’re all aware of Perl’s little warts but not using Perl because of them is a bit like insisting on not using Python for its whitespace rules. In actual day-to-day programming this sort of thing in Perl makes very little difference to real programs that real people actually write.

    What does make a difference is being able to write a program in a day that you’d otherwise spend a week on because you could leverage 20 well-written CPAN libraries while doing so. That’s why people keep using Perl and it’s something that’s only recently starting to get matched by other languages.

  16. >> Could you please tell us when would you actually want to call reverse twice?
    > When you are trying to understand how a language works.

    When you’re trying to do something (like reverse reverse), and it doesn’t work, the language’s documentation should be where you go instead of holding up a flare and saying “HA! RUBY W1NZ 4GA1N!”.

    From `perldoc -f reverse` (or google “perldoc reverse”):
    “In list context, returns a list value consisting of the elements of LIST in the opposite order. In scalar context, concatenates the elements of LIST and returns a string value with all characters in the opposite order.”

    This actually makes a lot of sense.
    If I do:

    perl -le'print reverse "the order", "of", "these", "words"'

    I will get the words in reverse order.

    If I do:

    perl -le'$a = reverse "letters"; print $a'

    I will get the letters in the word in reverse order.

    Perl allows you to do so much more, very efficiently. It seems to me (and excuse me if I’m wrong) that you simply don’t want to read documentation, because complaining suits you better. Same goes for this childish post. Well, that’s great for you. All you needed, if you cared, was to read two sentences (TWO SENTENCES), available from any command line, google search or firefox address bar (which defaults to the first result of a google search).

    BTW, to reverse the letters of a word twice, you simply need to tell the second “reverse” function to think of it as a scalar (a single word) instead of a list. This can be done as such:

    perl -le'$a = reverse scalar reverse "hello"; print $a'

    You can also tell the first “reverse” function that you want a word back straight when printing:

    perl -le'print scalar reverse scalar reverse "hello"'

    Contexts are not easy to grasp at first (and pinning down “scalar” words in your code seems atrocious at first) but once you _understand_ them, they allow you flexibility which you can really appreciate.

    … unless of course you just wanna talk trash, that’s cool too, I’ll just get out of your way. :)

  17. Sawyer says:

    to reverse the letters of a word twice, you simply need to tell the second “reverse” function to think of it as a scalar (a single word) instead of a list. This can be done as such:

    perl -le’$a = reverse scalar reverse “hello”; print $a’

    You can also tell the first “reverse” function that you want a word back straight when printing:

    perl -le’print scalar reverse scalar reverse “hello”‘

    That word “simple” — I do not think it means what you think it means. Your example amounts to “All you need to do to make the Perl version work is simply sprinkle random magic incantations through the code!”

  18. Now this is a good debate.

    Basically what you’re saying is that my “simple” isn’t so “simple” to you. That’s fair, I can understand it.

    There is always a trade-off between features and easiness. You either provide more features and supply more power to the user at the risk of making it not-as-easy-as-they-would-probably-initially-think-it-will-be or you provide it as easy as it would seem at first, but to try and do something more elaborate or complex, they will either need more steps, more variables, or more lines.

    Perl is obviously on the “more power, less intuitive at first” side. I’ll admit to that, and I’m personally okay with it. I like the ability to know what a variable is in the depths of someone else’s program simply by looking at it (sigils have a purpose), it’s fun that I can do a lot of things without running into multiple variables or multiple steps.

    I can understand how you would feel it should be as simple to use as possible, which is occasionally the opposite side of Perl. That’s cool with me. :)

    However, this is a feature of the language, a design decision to allow more fingergrained selection to the developer (which yields excellent DWIM paradigms) instead of a faulty imposition, which is what the post (and your initial comments) suggested.

    P.S.:
    I probably passed off as an asshole at first, so sorry about that. :)

  19. Sawyer, no problems with the tone of your previous comment :-)

    It’s true that one man’s simple can be another man’s complex; it’s also true that there is generally a trade-off between features and easiness, although that is by no means universally followed: very simple languages like Scheme can be the most featureful, too.

    In this case, though — Perl’s notion of scalar and list context — I’m afraid I am sticking by my original reading, which is that this is Just Plain Broken. It’s in the very nature of expressions that type information percolates out from the atoms (e.g. adding two integers yields another integer); by respecting scalar/list context as well, Perl has to look in two directions at once to figure out the type of any given expression — down to the subexpressions that make it up, and up to the context in which it’s being evaluated. No wonder it badgers it up sometimes.

    Look again at the Ruby code in my earlier comment, and try to tell me, hand on heart, that it’s not just just plain better.

    BTW., I assume that you’ve seen the other short articles in this series, and understand that my purpose here isn’t to pick on Perl in particular. As I’ve noted elsewhere on this site, it’s been my language of choice for a decade, and most of my own free-software releases (see the link below the banner) are in Perl. But that doesn’t mean I am blind to its faults.

  20. I respectfully disagree.

    Broken means “we tried to do something and failed.” Perl’s usage of context might be confusing or frustrating but it is by no means (or by any dictionary definition) “broken”.

    It works – as intended, but yields results which are sometimes not as you would wish them to be. This isn’t broken, this is (at most) annoying.

    Regarding your Ruby code, it is indeed beautiful. I can honestly say that in a module I wrote, being able to return either an array or an arrayref (a single scalar) according to the context of the user is also very beautiful for me.

    return wantarray ? @entries : \@entries;

    It’s not about who can provide the most beautiful piece of code (I’m sure you would agree that’s just ego talk). It’s about whether context is useful, and whether it works. It’s useful, it works. However, even nice things (like context-based returns – which is truly kickass, IMHO) can bite you on your ass if you’re not careful, as having dogs and cats taught me over the years. Somehow, my parents still raise dogs and I still have cats – even though I got my fair share of bites.

    And I don’t have a problem with picking on issues with Perl. I think it can really help us all progress, but there are wayyyyy better things to pick on than something which you simply don’t like. :)

  21. Sawyer, you’re right that it’s not about who can write the most beautiful code; it’s about languages enabling you write clear code — code that doesn’t have to be explained, either by inline comments or by subsequent advocacy. I think you’re doing a fine job of defending Perl’s dumb notion of context, but your attempt is doomed — not because I am a better disputant, but because it simply does not make for comprehensible code. It’s one of the reasons that Perl is often (unfairly IMHO) characterised as a “write-only” language. If you’re arguing that the notion of context isn’t broken because it “works as intended”, then all you’ve done is shown that it is, to use an old IBM acronym, BAD: Broken As Designed.

    Finally and most importantly, this: “I don’t have a problem with picking on issues with Perl [...] but there are wayyyyy better things to pick on than something which you simply don’t like”. What I’ve obviously not managed to get across yet is that context is just one symptom of a much more systemic disease, namely that (to quote the manual that started this whole thing off), “There is no rule”. Perl contains, well, whatever Larry thought was a good idea at the time. It totally lacks consistency. Now I fully understand that this is deliberate: Perl is Pathologically Eclectic by design; but saying that this is deliberate is not an excuse, much less a defence; it’s an anecdote.

    Here is the consequence: in learning Perl, you have two choices. You can just plough in without making any attempt to understand what’s happening, and trust that “they do what you want” — an usually that’ll work OK, because what you want quite often coincides with What Larry Wanted That Day. But if you want to understand more fully, you have to make a big leap to fully grokking Perl contexts, references, objects and all the rest. The learning curve is a step: very shallow to beging with (which of course is good) but then a sudden vertical leap. Other languages (and here I admit I have Ruby in mind, but it’s far from unique), being consistent, are much easier to grok on the kind of deep level that Perl, while it admits, does not invite. In short, Perl’s inconsistency is a short-term win for DWIMming, but bites you when you start to need to do more.

    It’s been a great language — one of the two or three real success stories of the last decade. But the sun is setting on it; it’s accumulated too much bolt-on crudulence along the way to recover the kind of unity of thought that a good language needs. The Perl 6 reboot might have saved it, but it’s taken way, way too long, and no-one is betting on that any more: not now that so many alternatives are available.

  22. Check this:

    > perl -Mstrict -Mwarnings -E’my $foo = “hello”; ($foo) = reverse reverse $foo; say $foo’
    hello

    > perl -Mstrict -Mwarnings -Mautobox::Core -e'”hello”->reverse->reverse->say’
    hello

    Perl’s problem is needing to cut down on the boilerplate, but the concept of context isn’t.

  23. I’d not encountered Perl’s autobox pragma, or the autobox::Core module, before — thanks for the pointer. I read up on them on search.cpan.org and they are fairly cute. Sadly, though, they don’t seem to be very mainstream yet: my Ubuntu 9.10 box doesn’t seem to have a package for them, for example.

  24. If there’s an inconsistency, what *should* sort return in scalar context then? You never answered my first questions.

  25. Aaron Davies

    @Ævar: yeah, that sounds familiar. i’m not surprised there’s a way to do it without temporary variables, but nor am i surprised that i couldn’t figure it out. :)

  26. Aaron Davies

    @Mike: i’ve often felt that perl is less a language and more a collection of twenty years of special cases. (which isn’t to say that there aren’t some problems where it’s the best solution….)

  27. Chromatic asks: “If there’s an inconsistency, what *should* sort return in scalar context then?”

    I unask your question. The whole notion of “scalar context” is a mistake. Once that is eliminated, your question becomes “what *should* sort return?”, to which the obvious answer is “a list, of the same type as the one it was invoked on”.

    Once more, in nearly every language, the type of an expression is determined by its consituent subexpressions, not by the context it appears in. The result of sorting an array is an array. THAT rule is easy to remember — in fact, there is nothing TO remember, because it’s just one instance of a uniform metarule.

    The reverse example is better, because that function really is polymorphic: it can apply to strings and lists (and maybe other types) and really should return something different in the different cases. But they are all simple:

    "foobar".reverse -> "raboof"
    [1, 4, 9].reverse -> [9, 4, 1]
    "foobar".reverse.reverse -> "foobar"
    [1, 4, 9].reverse.reverse -> [1, 4, 9]

    Because the type of the result of reverse is determine by its argument, not its context.

    I come back to Dijkstra’s maxim: “The competent programmer is fully aware of the strictly limited size of his own skull; therefore he approaches the programming task in full humility, and among other things he avoids clever tricks like the plague.” Most people (you may be one of the exceptions) can’t consistently wrap their minds around the inconsistent model that Perl offers; the strictly limited sizes of our skulls require a simpler, more consistent model to follow.

  28. Appealing to the relative popularity of a design feature in a superficial survey of other (unnamed) programming languages is … well, you might as well compare Haskell to a lot of imperative languages and argue that type inference is a mistake, or that RPN in stack-based languages is a mistake, or that Smalltalk’s order of evaluation is a mistake, or that Lisp’s homoiconicity is a mistake, or that void evaluation context in C is a mistake.

    As for context being too difficult to fit into your head, if you can finds the error in these clause, you had a fine understandings of context in the English languages.

  29. Context in English languages does not work remotely like context in Perl. In phrase structure grammars, type information percolates out from the interior of each nested structure just as it does in good programming languages (you just have to deal with multiple potentially ambiguous parses to figure out what the structure *is*, and some elements of that structure may be represented only by invisible ‘traces’ in the eventual sentence, due to phrasal motion.)

    Yes, it’s true that outer components often want particular types in their slots, but that doesn’t mean that it can freely change an NP into an ADJ because it’s expecting an ADJ there dammit.

    (I’ll turn the linguist geekery off now, it’s off topic. But Perl boosters bring up this argument over and over again, just because it’s Larry’s only argument for the existence of context in the camel book, and it’s completely flawed. Also… natural languages take humans years to learn, even though we have an instinct for it: perhaps computer languages should in general not be so baroque?)

  30. @Others,
    Perl is still widely used internally in any organization. Even for that matter, still Perl Tk is widely used for GUI’s. Python, Ruby suffer from GIL. C and C++ are good for system level users. Java is burnt in the hands of Oracle. Golang is having few libraries. D doesn’t interest many. Erlang, Clojure and Scala are useful to certain section of companies only. “Perl is powerful having weapons that could be put to wrong use” and that is what Mr.Mike Taylor is saying. Now, we have two choice regarding a language’s usage:
    Choice 1: Give weapons to people ‘without proper access and usage rules’ and ask them to use judiciously.
    Choice 2: Give weapons to people ‘with strict access and usage rules’.
    Choice 1 would hit us if one is not careful. Hence, consistency should be an agenda in the upcoming versions of perl so that all users will be benefitted.

    @Mike Taylor,
    You are true ! But ?!
    Please understand that perl is rocking in many sectors of science and Modern::Perl, MOOSE, Catalyst have already taken perl to great heights.
    I can’t find too many Ruby gems for many tasks I need (GUI’s, higher statistics). Also, Ruby is slower than perl. Merb , RoR merging is confusing. May be till such time it covers up, we may have more modules in perl and also syntax changes in its versions. Also, u have used perl for 10 years to earn bread (either partially or fully). So, can you take sometime to ‘suggest solutions’/discuss the issues you find in the syntax to the team working in perl 6? If you do that users like me benefit a lot.

    Cheers have a beer!!

  31. Truman, much of what you say is true — I was disappointed recently, for example, when I couldn’t find a Ruby module to calculate a simple correlation coefficient — but the bottom line for me is that I’m out of love with Perl; Ruby’s strengths are mostly in the same areas as Perl’s, and it’s Just Plain Nicer. It will catch up in the areas where it currently lags behind, and issues like its supposed lack of speed are not issues for me. I’ll always be grateful to Perl for getting me out of the low-level-languages-for-everything mindset, and no doubt I will still be occasionally hacking Perl programs in 10 or ever 20 years from now. But my heard belongs to Ruby.

  32. Pingback: The Perl Flip Flop Operator « A Curious Programmer

  33. Interesting, Mike Taylor.

    $foo = reverse reverse 'hello';

    So you write that kind of code often? Do you also write

    if (!! $foo) { ... }

    for no apparent reason? I’d love to hear the rationale for writing

    $foo = reverse reverse 'hello';

    . ;-)

    Seriously though, have you ever been bitten by that behaviour in real code?

  34. Idran,

    Yes, absolutely I have been bitten by Perl’s complex and misguided attempts to “do what I mean”; if you are a Perl programmer who has written more than trivial scripts, I bet you have, too. The specific example given here, reverse reverse, is a deliberate boiling down of one such issue into its simplest, most comprehensible form. Here’s another example of the same kindf of thing: consider this program:

    sub ret2 {
        return "foo", "bar";
    }
    
    my @res = ret2();
    print "res has ", scalar(@res), " elements: ", join(", ", @res);
    

    As you’d expect, this yields: res has 2 elements: foo, bar. But if you change the single-line body of the ret2 function to:

        my @tmp = "foo", "bar";
        return @tmp;
    

    The program yields res has 1 elements: foo. Change the first of those lines to:

        my @tmp = ("foo", "bar");
    

    And suddenly res has two elements again.

    You can’t tell me that’s a decent way for a programming language to behave. Yes, I know and understand that such behaviour emerges from the interactions of rules which all seemed like good ideas at the time, that they were all added with the best of intentions. But the upshot is … really really not good.

  35. Mike,

    The point is that Perl’s idea, whether executed with perfection or not, is to sacrifice some consistency to gain some practicality. Then it is obvious that you can find some weird case which surprises you, but unless it’s code you actually write it then its not a problem. No one will ever write “reverse reverse” in real code, I hope, so that critique is a bit off mark.

    Your other point is about operator precedence, and there’s nothing inconsistent about it. In Perl = binds tighter than ,. Nothing strange about that. It’s just two operators.

    What do you expect y = f x + 1 to do in Haskell? Ruby programmers might parse it as y = f(x + 1), but Haskell has a different binding. Is Haskell indecent? Or should Ruby programmers just think Haskell instead of Ruby when they read/write Haskell?

    In general you can’t just substitute a function call with the code on the return statement as in your example. If you’d have

    sub foo { return 2 + 3 }
    my $x = 2 * foo()

    would you then expect

    my $y = 2 * 2 + 3

    to be the same as $x? The use of a parenthesis to overrule operator precedence is hardly a foreign idea …

    Coincidentally, in Python you can write

    x, y = 3, 4

    but in function calls you write

    foo(x = 3, y = 4)

    and not

    foo(x, y = 3, 4)

    This is not critiquing Python; it’s two completely different things and personally I have no issues with it (I use both Python and Perl). In Python = isn’t an operator in the same sense as Perl’s or C’s assignment operators (e.g. you can’t do a = b = c in Python). In practice I don’t even have to care since I hardly ever write assignments like that. I only unpack tuples like that when the RHS is an expression returning a tuple (just like when Perl returns a list and you use list assignment).

    There is legitimate critique, using real-world examples, that causes hard-to-track bugs (I could give an example in another reply if requested; this reply is long enough), so there’s no point in using shallow examples to show that “Perl is weird”. However, once you’re been bitten by the context sensitivity bugs during your first acquaintances with Perl it usually ceases to surprise you, often because you start to write Perl in Perl, not pseudo-C, pseudo-Java, or some other kind-of-similarly-looking language that you expect Perl to behave like. If it doesn’t/didn’t cease to surprise you, then … well … my condolences. :-)

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s