> Global variables abound.

There's a couple, but mostly just if you want to hack something, and usually there's another way to do it. They're useful for one-liners, but if you're doing it in production, you're usually doing it wrong.

Sure, you can use them, just like you can do some stupendously bad things in most languages. Perl does give you more options for that, but the trade-off is that you can often do quick testing or one-off processing from the command line with one liners.

E.g. Maybe you might run into $| (AKA $OUTPUT_AUTOFLUSH) or $/ (AKA $INPUT_RECORD_SEPARATOR) because those are useful and common. The rest are holdovers from awk. If you see them often in your code base, someone did you wrong.

> Crazy cryptic syntax.

I find it usually pretty straightforward, but that's how I write my Perl. The Perl I write these days is usually functions full of params with validation. E.g.

use Function::Parameters qw(:strict);
...
fun find_changesets_after(
DateTime $last_processed, # No default, so required
Maybe[DateTime] :$cutoff = undef, # :$ prefix denotes named variable
Bool :$debug = 0,
HashRef :$cache = {},
) {
# just use $last_processed, $cutoff, etc without instantiating them
...
}
# Called like so
find_changesets_after( $last, cutoff=>$not_after, cache=>$CACHE );

That's a bit on the complex side, but it's a far cry from what I was writing 20 years ago, and in a good way. The language is marching forward, sometimes through code advancements, sometimes through best practices modules (Moose, etc).

> Ridiculous scoping rules with hacked on workarounds.

Err, what? The scoping rules are almost the same as C. There's some weirdness with $_, but don't go crazy with nested functions in maps and greps (and name your loop variables otherwise) and it's usually fine.

> When someone hands me a perl script I don't look forward to trying to get it to work.

Well, neither do I, because usually when I've been "handed a $LANG script" it's because it's problematic because it was written based on differing business requirements at a past time, or by by someone that was under extreme time constraints, or someone that didn't know what they were doing, or some combination thereof. So yeah, being handed a script can suck, just like being handed any codebase can suck.

If you were being handed scripts that you are just expected to run and use but aren't working, it sounds like someone didn't include or define the dependencies. If they did, there should be no problem, since a vanishingly small number of things could cause a Perl script written in the last two decades to not work anymore. Backwards compatibility is taken very seriously.

Based on the time period you're talking about, it sounds like you got handed a lot of hacked together CGI's and system scripts that were the glue for the beginning of the web. I feel for you, I got handed a lot of the same. Keep in mind a lot of it was written by Perl novices, extended by Perl novices, and then left to age ungracefully. Perl was everywhere in the late 90's, and a lot of beginning programmers were being thrust into tasks they didn't have a lot of experience for, so it makes sense that the average quality of a Perl program during this period would be very low.

> NPM might suck for various reasons but at least all deps are installed local to each project. I'm sure there are secret incantations for doing the same in perl and python but by default most stuff I download requires global libraries to be installed.

In Perl it's "cpan install $MODULENAME" or "cpanm $MODULENAME" (now) and it will download, compile (if required for bindings), test[1], and install all dependencies. Perl's had this done well for almost a couple decades too. For module authors, on uploading a module it's automatically spun out across a testing network and tested across a large matrix of Perl version, operating systems, and architectures, and the results are emailed to you (and visible online).[2] The cpan command was the appropriate way

There are valid criticisms of Perl, but I you have to set the bar pretty high to find major faults in CPAN (at least compared to contemporaries).

> If there is one thing I love about npm is that it defaults to project local installs and I have yet to run into a project that requires a global install

I've not run into a global module install problem in Perl in... well ever. It's supported local modules fine since I first started using it in the late 1990's.

If you're talking about interpreter installations, that use dto be much more painful (you had to actually install them and manage them manually), but since 2010 there's been perlbrew (inspired from the equivalent in Ruby or Python, I believe), which automates all this, allows multiple interpreters and libraries, etc. It sounds like that was past the time you were using the language, which is a shame, because it's really nice.

I think you'd be very surprised at the average level of Perl code these days. Part of that is a community that's not getting a huge amount of new blood, so the people that are left are mostly veterans, but that has some benefits at least, as few as they are.

1: And fail if the module or a dependency's tests fail (unless you specifically force it), as is right. If a module can't pass it's tests, you sure as hell don't want it 6 levels deep in a dependency chain acting oddly.

2: http://matrix.cpantesters.org/?dist=Path-Tiny