1. 18
  1.  

  2. 14

    Conclusion: Do you still hate Perl? It’s easy to hate what you don’t under­stand.

    Yes, I still hate Perl. The author optimistically hopes that Perl hatred is simply due to not understanding the language, but the problem is really with Perl itself. Perl is a very weird and idiosyncratic language. Mainstream languages have converged on simple, easily understood conventions for how to write code. Perl ignores these conventions, replacing simplicity and composability with what to me looks like poorly designed, overly complex garbage. Suppose I want to compare two values for equality. In Python, I would use the == operator. All the following expressions return True:

      42 == 42
      "abc" == "abc"
      [1,2,3] == [1,2,3]
    

    In Perl, you use eq to compare strings, you use == to compare numbers, and I no longer remember how to compare lists, but I do recall it’s weird and complicated, because lists aren’t values in Perl. Perl just has no uniform way of operating on values, and sigils are one of the symptoms of this. The real problem with sigils is not the syntax, it’s the semantics.

    For me, the question is not, why do people hate Perl, but why does anybody like it? Here’s my theory: I think that if Perl is your first significant programming language, then your brain becomes wired to understand Perl, in all its weirdness. At this point, you will like Perl, and probably you will find mainstream languages less comfortable to use.

    In my case, I already knew a dozen or more languages before I found myself in a role where I needed to write a whole lot of Perl code from scratch. It was agonizing, and the pain of writing Perl did not go away with increasing familiarity. It’s the worst general-purpose language I’ve ever used.

    1. 4

      I had never thought of it before, but I think your theory is correct. Perl was the first significant language I learned. I had written some Python scripts, but Perl was the first real codebase I had to work with and so I had to really understand what was going on in the language.

      At this point, you will like Perl, and probably you will find mainstream languages less comfortable to use

      This was true for a while, but I would add since Perl has the TIMTOWTDI mentality, that learning new languages felt easier since they did not have the same punk rock kind of attitude. My attitude to a new language tends to be, “there are no rules, so just tell me how you want me to do it and I will do it that way.” With Perl, you don’t get any rules. It is similar to C in this way (which I would also categorize as a punk rock language).

      Still, your theory is correct because, while I do not write Perl anymore, I do still think given a problem I could crank out a Perl script to do whatever is needed faster than in another language. A beautiful, ugly, working Perl script that will live forever out of fear of rewriting it!

      1. 3

        Perl wasn’t my first language (that was C) but it was the first one I made much progress with. I used it for a couple of years before moving on.

        A long time later, perhaps 15 years, I started to contribute to some Perl programs. I found it awkward at first, but once I’d refreshed my knowledge a little bit, I began to grudgingly respect it more. There are things about it which are well designed, and most of the code that you might reuse from CPAN etc these days is generally of a high quality. (The “modern Perl” book is very good, and doesn’t try to pretend it’s perfect).

        Perl is never my first port of call to solve a problem, but compared to shell (which is everywhere) and even to supposed successors like python, I’m often surprised that there’s a more elegant way to do something.

        The only reason to relate my anecdote is because I don’t think I fit your theory.

        1. 2

          Use java, you get .equals vs ==, the latter comparing the pointer of String objects.

          1. 1

            I wonder if Perl is the Cruelty Squad of Programming languages?

          2. 7

            I hate Perl, but none of these are in the top three reasons.

            Fragile datastructure creation and dereferencing syntax is #4. I don’t know why anyone would defend it because it serves no useful purpose for the user. It might be okay if the compiler told you that you are using wrong dereference incantation for the value. However, it brings us to #1.

            Perl is essentially untyped. Even with strict and warnings there’re lots of errors that will pass undetected and will only manifest in incorrect behavior. That’s my reason #1.

            The second reason if lack of good ways to express abstraction through either types or objects. Hashes that pretend they are objects don’t count, and third-party bolt-on solutions aren’t that much better.

            The third one is lack of a good module system.

            For the record, I let a big rewrite from Perl to Python and it saved the project from crumbling under its own weight. I’m not a casual Perl hater. ;)

            1. 3

              Hashes that pretend they are objects don’t count

              I’d like to understand more about this. Do you have the same reaction to javascript, which I think has a similar model? Could you elaborate on why they don’t count?

              and third-party bolt-on solutions aren’t that much better.

              I’ve not looked for a while, but things like Moose (https://metacpan.org/dist/Moose/view/lib/Moose/Cookbook.pod#Basic-Moose) seem to meet a lot of needs - could you give an idea what is lacking?

              The third one is lack of a good module system.

              I’d appreciate understanding more about this. CPAN was pretty much setting the standard for module creation and distribution before any modern alternative.

              There are lots of opinionated aspects to perl which people can reasonably dislike/disagree on - I’m just a bit surprised by some of the above.

              1. 4

                Do you have the same reaction to javascript, which I think has a similar model?

                Yes. JS and Perl have one thing in common: they were designed (or thrown together) as languages for short scripts, and then people started using them for large applications, but, as Perlis said, a language never leaves its embryonal sac. All you can do is work around those issues, not fix them.

                Why it doesn’t count? Because it doesn’t really provide you with a way to either express the data model or enforce it.

                things like Moose seem to meet a lot of needs

                At the very least, you have to force them on people. Since it’s not a standard, and not even very widespread, that will be writing in “Perl with Moose”, not in Perl.

                CPAN was pretty much setting the standard for module creation and distribution before any modern alternative.

                I mean a module system at the language level, not a way to download chunks of code. By that logic, JS has a good module system because there’s NPM. It doesn’t. If you haven’t seen a good one, look at Ada or ML, or at least at Java or Python.

                1. 5

                  I mean a module system at the language level

                  perl has package scoping, language constructs to import sets of symbols from one package into another (or refer to them with a package prefix).

                  Because it doesn’t really provide you with a way to either express the data model or enforce it.

                  Are you objecting to the lack of enforcement of public/private (the perl convention is leading underscore for private, but it isn’t enforced. Although C++ doesn’t enforce it either if you #define private public before including the header file…)? Because you can have types with fields, methods on objects, class methods, constructors, destructors.

                  Is it the lack of static typing you dislike? Does that also apply to python without type hinting? (Sorry for the many questions. Many people dislike perl for different reasons - and that is fine - but your reasons are different to most :-) )

                  At the very least, you have to force them on people. Since it’s not a standard, and not even very widespread, that will be writing in “Perl with Moose”, not in Perl.

                  No? You don’t need to force them on anyone. Like common lisp, the underpinnings of perl (at the language level) are quite powerful and allow people to build powerful extension modules. This can lead to some fragmentation, but the community made reasonable efforts to promulgate good practice, e.g. https://en.wikipedia.org/wiki/Perl_Best_Practices

                  I think there are reasons to dislike perl, but I don’t think lack of power in the type system is one of them (unless you are just against dynamic typing in general, which is perhaps a different position than “perl is bad because it doesn’t have real types”).

            2. 6

              None of these are particularly convincing to me, as someone who has seen some Perl code and heard more complaints but hasn’t written any.

              1. Perl regexes that I’ve seen are not easily readable. If they are readable when done well but nobody does them well, then the problem is that it’s too easy to use them badly, which is a language design problem. It’s true that regexes in other languages aren’t especially readable either, but as he says, regexes are much more deeply embedded in Perl than other languages, so it’s a bigger problem.

              2. Sigils seem pointless and at the wrong level of abstraction to me. If it’s a simple data structure, I’m not going to forget what it is. If it’s a complex data structure, I don’t want to constantly think of it as a hash or an array, I want to think of it as the data structure it actually represents. Ruby’s use of sigils to differentiate between instance variables, class variables, and so on makes more sense.

              3. I don’t have a problem with the dereferencing syntax mentioned, but it brings up a different question. Let’s say I have an array @array. I want the third element, and I want to store it in a variable. What sigil do I use, if I don’t know the structure of the array? I assume there’s a solution but it seems needlessly complicated that you have to worry about it.

              4. The argument here is “if it bothers you you can use English;” except most of the complaints around perl have to do with readability, and if you’re reading the program of someone who didn’t use English; it doesn’t help that the option is available.

              1. 5

                Sigils seem pointless and at the wrong level of abstraction to me. If it’s a simple data structure, I’m not going to forget what it is. If it’s a complex data structure, I don’t want to constantly think of it as a hash or an array, I want to think of it as the data structure it actually represents. Ruby’s use of sigils to differentiate between instance variables, class variables, and so on makes more sense.

                Perl has roots in linguistic thought [*], so $ and @ are more reasonably thought of as “singular” and “plural” rather than as data types. These provide a ‘context’ to the surrounding code, which perl (uniquely) leverages. Having the context be explicit in the sigils helps understand this process.

                https://www.perlmonks.org/?node_id=738558

                Complex data structures are captured in rich dynamic types with fields and methods, just as in other languages. The same plural and singular context applies to them too.

                [*] e.g. many methods will operate without an argument, and use the default argument $_ which I pronounce “it”.

                my @a = (1,2,3);
                say for @a;
                

                Here “for” is looping over @a. The for loop aliases “it” to each value in turn. “say” is invoked on each iteration without an argument, so it uses “it” and prints it.

                1. 2

                  scalars are singular and arrays are plural, and the sigil is meant to provide context

                  That certainly is a much better explanation for it than the article presented. Why are hashes given a different sigil, though? And why does the other responder say they never use arrays, if they’re one of the two main contexts?

                  1. 6

                    Why are hashes given a different sigil, though?

                    That’s a good question. I find that in perl code, you rarely see a hash sigil except as a declaration. It provides a list context to the RHS of an assignment. Assigning a list to a hash takes alternating elements as key/value.

                    And why does the other responder say they never use arrays, if they’re one of the two main contexts?

                    Plural context is more properly called “list context” (https://perldoc.perl.org/perldata#Context, https://docstore.mik.ua/orelly/perl4/prog/ch02_07.htm, https://docstore.mik.ua/orelly/perl3/lperl/ch03_08.htm) and is more general than arrays.

                    Although, to be honest, I used to use perl arrays all the time. With push/pop and shift/unshift they filled the role of lists, queues, dequeues and vectors in terms of ease of use (I don’t think you can properly fulfill algorithmic complexity of all of those with one data structure, but specialist needs can pull in other modules with those characteristics).

                    e.g.

                    # Seed the work list
                    my @todo = ($path);
                    # Take one item from the front of stuff to do, finish if no more work
                    while (my $next = shift @todo) {
                      #  Get zero or more work items from doing this one
                      my @additional_work = process_file($next);
                      # append new work items
                      push @todo, @additional_work;
                    }
                    

                    Perl’s philosophy is at odds with programming language development since the early 2000s. “There is more than one way to do it” (TIMTOWDI) also “Easy things should be easy, hard things should be possible” a.k.a. Huffman coding for the programmer. Python had broadly the opposite approach (“one way to do things”, “explicit is better than implicit”) and was more in tune with the way the world went.

                    This leads to a language with a very different approach and culture to others. One can rightly criticise perl for having many ways of doing things (just as one can rightly criticise C++ for the same reason). That is a strength and a weakness, mostly a weakness at scale, where a new dev might have to understand a large amount of the language to read code. But to a newbie, learning to write code, it can be an advantage.

                    List context and abbreviation also enabled powerful map/filter tools some time before python got list comprehensions, and when such things were more a province of the lispers. (perl also had proper closures before many other languages - https://www.amazon.co.uk/Higher-Order-Perl-Mark-Dominus/dp/1558607013). Perl hashes (a.k.a. dicts, maps) “auto-vivify” so you don’t need to handle the uninitialised case. Some code to calculate distribution of word lengths:

                    #!/usr/bin/perl
                    use Modern::Perl;
                    
                    my @words = qw/the quick brown fox should be nicer to the lazy dog/;
                    my %lengths;
                    $lengths{$_}++ for map length, @words; # length takes $_ as arg, provided by map
                    foreach my $k (sort keys %lengths) { # list context operators (keys, sort - compose naturally)
                        say "$k => $lengths{$k}";
                    }
                    

                    One might think that one can control the breadth of the language in large projects with coding standards, but both perl and C++ arguably fail here.

                    But perl was (and is):

                    • concise
                    • expressive
                    • fast (compared to other languages in its niche - i.e. python + ruby. JS got a big speed bump later)
                    • well designed (although one may disagree with the design goals)
                    • fun
                2. 1

                  Re point 3

                  my @array = (1,2,3,4);
                  my $third = $array[2]; # 0-based indexing, referencing a single entry returns a $calar
                  my @first_last = @array[0,3]; # slice returns an @rray 
                  

                  To be honest, outside of introductory programming and (in my case) coding contests, arrays are rarely used other than indirectly. The true workhorse of Perl is the hash(reference).

                  1. 1

                    It’d work for a hash as well, but my question is a bit different: If you have a data structure you fill at runtime, so sometimes it could be (1,{'a' => 'b'},2,3) but other times it could be (1,2,{'a' => 'b'},3). Or any other access pattern where you have a heterogeneous array, or a hash where the values are of different types. And you access $array[2]. Since you don’t know if it’s a scalar or a hash, what sigil do you use for the variable?

                    1. 1

                      Well to be pedantic, {'a' => 'b'} is a reference to a hash, which is a scalar, so it would be $third in either case. Of course it would sometimes be an integer, and sometimes it would be a hash reference, but that’s a separate (more serious) issue ;)

                3. 4

                  Reading that article just brought back really painful memories of trying to grok a large and complex Perl codebase written by 4-5 different very smart people with different ideas of how they wanted to lay out the code and reference data. Arguably, I dislike the language more after reading that, mostly because I had partially forgotten how horrible it was to maintain anything written in it.

                  1. 3

                    I’m going to hide this, because the post didn’t manage to change people’s mind (all of the world’s problem could be solved if we could ever do so), and the comments here infuriate me (some people just hate foreign languages; all of the world’s problem could also be solved if we could ever do so).

                    1. 2

                      I used to use perl all of the time. I think it was my first dynamic language that I really leaned into. Then I “grew up” into python.
                      Now I like perl again, and think python is too grown up. For big projects I’ll use lisp or golang, but anything up to that is now back in perl.

                      1. 1

                        I don’t hate Perl, but I’m deeply ambivalent towards it. It had a niche which was basically “imagine if we took awk, sed, and shell scripting and turned it into something resembling a proper language”, and to be fair, it managed to do a lot with those foundations. But it never quite outgrew them, and the last attempt to do so almost killed it as a language.

                        For text munging, few languages come close, but I haven’t felt the need to reach for it in over a decade.

                        1. 1

                          I think one thing that makes Perl hard to read is Perl’s idea of list/scalar context, which I believe is a form of ad-hoc polymorphism. jbert posted this link introducing scalar/list/void context in Perl: https://www.perlmonks.org/?node_id=738558

                          The article makes it sound like sigils are just clarifying what type things are, and wouldn’t that improve readability? But because of context, sigils in Perl aren’t just like type annotations that help clarify and double-check what’s already going on, rather they are actually choosing which of the overloaded meanings of the annotated expression is being run.

                          Some other programming languages have ad-hoc polymorphism based on how the value of an expression is later used, as well. In my opinion this can be powerful but can make things less readable; you can no longer understand code by “single-stepping” with your eyes from the first thing computed to the last.

                          1. 1

                            But because of context, sigils in Perl aren’t just like type annotations that help clarify and double-check what’s already going on, rather they are actually choosing which of the overloaded meanings of the annotated expression is being run.

                            I like that description. They don’t describe the variable at all, since you can change sigils on foo at will. They’re closer to casting an expression.