Sure, if you're coming from structured Pascal 101, that might be an issue, but in the day where deeply nested functional rat kings tend to replace the humble WHILE loop, is a Schwartzian transform that confusing?
And implicit variables. Also, implicit variables. Composed types didn't make it any easier; and references, that broke all the logic implicit on the sigils.
Oh, and did I mention implicit variables?
As for implicit variables, I rarely see anything else than $?, $|, $_ and @_, of course. And I'd argue that $_ often makes code a bit easier to understand than cluttering it up with a variable declaration. No worse than point-free programming in more modern languages.
Don't get me wrong, I don't think that Perl is that well architected and that Perl5 would've required some more courage at dropping backwards compatibility, but what I don't get is why Perl is singled out here. It's not that radically different like e.g. APL or ScalaZ.
Compared to other languages of its day, this feels a bit like the "Reformed Baptist Church of God, reformation of 1915" joke. Then again, perfectly fitting into similar conflicts about brace styles or 1-based indexes…
Both of what never got as much popular.
Perl is singled out because it was used. And too often on short scripts that grew into thousands of lines, so the problems showed up.
Now, Python on the other hand...
It fixes a hole lot of more important problems, but it's mostly aimed at problems that will make your code misbehave, not the ones that will make it hard to read.
They don't break the logic, they just follow different logic than many people assume. Either you're indicating a collection (a hash or array), or you're indicating an item. @ is a plurality indicator, while $ is an individual indicator. You reference the single item of the @foo array with $foo[0] for the same reason you say "the first apple of the bunch" instead of "the first apples of the bunch" when you want the first one. Yes, it's probably better not done that way (it's not something you can usefully change in Perl 5 at this point), but it does follow well defined rules, apparently just not the ones you assumed.
Implicit variables can usually be avoided (except for $_, but that's pretty normal these days, and I'm pretty sure it topical variables didn't begin with Perl), and often they're lexical so usually other people's code messing with them is contained. Except for $_ itself which isn't lexical, which is it's own story and a pain point. :/
C works similarly. What was the error from the last system call? "errno".
Certainly there are problems with this; we've all seen the programs that output "Error doing something: Success". But it isn't Perl that invented this. It's a UNIX tradition.
But the end result was horrible: everyone did "it" every possible way, and that, IMO, is the underlying reason for Perl's reputation for being unreadable.
I also think it had a great deal of impact on the development of later languages and principles, which tend to focus much more on removing freedom from the programmer and enforcing idiomatic ways of doing "it". Today, you're far more likely to encounter modern code written by different programmers which looks very similar -- at least on a line-by-line basis, anyway. At the architectural level, it's still a big game of Calvinball.
In my mind, it's down to it having been popular, attracting many amateurs. You'll find equally unmaintainable bash or PowerShell scripts and definitely as much garbage, WORN JavaScript code. Writing maintainable code requires both knowledge and effort.
[0]: https://metacpan.org/pod/Modern::Perl
[1]: https://metacpan.org/pod/Moo
[2]: https://metacpan.org/pod/Mouse
I worked in a company that had huge Perl codebase, which made extensive use of the Moose library. After trying to make sense of it, I gave up and used plain Perl, writing it as unidiomatic and simple as possible, so that hundreds of other devs, also new to Perl, would be able to understand the code I wrote. This was the common sentiment - most of the people followed the same path.
The library is just a nightmare - Perl is dynamically typed, there is NO adequate IDE support (compared to the one statically typed languages have), so good luck with working out how the library works underneath. And if I cannot understand that, how on Earth will I understand what even my code is doing? (Never mind the others')
In my mind, the amateurs are those that created the libraries without any idea on how they are going to be abused, thinking everyone should use unreadable incomprehensible syntax coupled with unapproachable internals.
I apologize for the rant, I had no idea this topic moved me so much.
Perl is great for text manipulation and one offs, not large, production systems.
return $foo->bar->baz;
to return Dwarn $foo->bar->baz;
which will 'warn' out the dumped structure and then return it, so you can instrument code for debugging trivially.DDCWarn also provides a DwarnT so you can add a tag that gets printed but not returned, i.e.
return DwarnT TAG_NAME => $foo->bar->baz;
There's not really a book on Moose, but the Moose::Manual pages plus Modern Perl plus The Definitive Guide to Catalyst work out pretty well between them for bringing people up to speed.I mean types do make software engineering craft a little tolerable and its not exactly a new thing to say here.
But how would this situation be any different than using Python or Clojure?
Talking of artificial bolt-on's. We are living in an era where we do 'from typing import *' and core.spec for Clojure all the time these days. How does this change only when it comes to Perl?
However, I still reach out to Python and Bash and Perl for some one-off tasks or gluing scripts and I do appreciate the brevity and clarity they bring for this sort of problems.
Except when it comes to building somewhat large systems (I am talking ~5 mil LOC here) - then every kind of "abstraction", like this disaster of a library Moose, only increases the complexity of the project by a large margin, and acts only as job-security for the original authors of the code, making most of the codebase impenetrable for the rest.
I have not worked with similar large systems in other dynamically-typed languages, so I cannot compare other languages to Perl in that regard. I do know, however, that Perl is simply a disaster to use in that scale.
I think most Perl developers would agree that if you expect you code base to reach in the millions of lines of code (at least if it's all one code base and not an ecosystem using an API), Perl (or any dynamic language) may be stretched to the point where its benefits are outweighed by its drawbacks, similar (on the other side of the spectrum) as if you used C/C++ to build a simple web app.
LOL, WUT? Why do you need IDE support to figure out how the library works underneath? You have the code, you have the docs, what else do you need to figure it out?
Over-use of meta stuff is something people often get tempted into when they first use Moose and can make things a bit more complicated, but the core syntax is honestly simpler and easier to use than raw perl OO and I've found it much easier to cross-train non-perl devs to Moo(se) style OO.
If you want an opinionated/terse syntax that encourages you to only be as clever as strictly necessary, I'd suggest looking at http://p3rl.org/Mu
Here's a small IO::Async + Moo app that I still consider to basically be how I'd write it today - I invite people to browse the source code and tell me what they do/don't find unreadable compared to more "raw" perl.
I guess if you do deliberate golfing/obfuscation you can make anything unreadable.
#Before enlightenment,
use strict;
use warnings;
#After enlightenment,
use strict;
use warnings; use strictures 2;
use Moo;
since strictures fatalizes most warnings as well as turning strict on for maximum "telling perl if I made a mistake to barf immediately rather than trying to be helpful and guess"