1. Sigils, and relatedly, contexts. In my opinion, `my $length = @list;` is a horrid way to spell `length = len(list)`. It feels too much like typecasting magic.
2. Having to opt in to pass by reference caused so much pain. You're happily passing a hash around, but then you want to do something to it, so now you have to change the type signature of the function, then everything that calls it, etc. etc.
Contrast with Python, where everything is pass-by-object-reference and sigils aren't needed because contexts in the Perl sense don't exist. This worked on my first try:
>>> a = ["foo", 123, {"bar": [(1,2,3), {"qux": "quux"}]}]
>>> a[2]["bar"][1]["spam"] = "eggs"
>>> import json
>>> json.dumps(a)
I liked Perl. I wrote a lot of Perl. And yet, I still had to pull out The Book whenever I wanted to do anything more complex than passing a couple of ints or strings around. This stuff is knowable, obviously, but I just got tired of having to know it.If one wants the function to mutate them, one has to explicitly mark them as `$x is rw` in the function signature; this then requires one to always pass a mutable container for $x. (A bit more detail: https://andrewshitov.com/2019/10/15/110-is-rw-vs-is-raw-in-r... )
my $a = ["foo", 123, {"bar" => [[1,2,3], {"qux" => "quux"}]}];
$a->[2]{"bar"}[1]{"spam"} = "eggs";
use JSON;
print(encode_json($a))
That's the same as your example (minus the tuple type), but where Perl shines over Python (a lot) is you could have done the following: use JSON;
my $a = [];
$a->[2]{"bar"}[1]{"spam"} = "eggs";
print(encode_json($a))
which would yield the json: [null,null,{"bar":[null,{"spam":"eggs"}]}]To do this in Python is truly grim:
import json
from collections import defaultdict
# recursive defaultdict using lambda
datastructure = lambda: defaultdict(datastructure)
a = [None] * 3
a[2] = datastructure()
a[2]["bar"][1]["spam"] = "eggs"
print(json.dumps(a))
and thats doing it the unpythonic way, if you were to do this like the typical Python dev would accept in an MR for a large corp you would have written: import json
from collections import defaultdict
def datastructure():
return defaultdict(datastructure)
a = []
# expand list to at least length 3
while len(a) < 3:
a.append(None)
a[2] = datastructure()
a[2]["bar"][1]["spam"] = "eggs"
print(json.dumps(a))
They would still hate you for defaultdict(datastructure) though. Because absolutely no one in Python realises its got that level of expressionism one of the few places it does. $a->[2]{"bar"}
The highest rated SO answer here explains a little, and it’s the kind of situational nitpickiness that let to me dropping Perl like a hot potato when something better matching my mental model came across my radar: https://stackoverflow.com/questions/1817394/whats-the-differ... $a->[2]->{"bar"}
which is equivalent and also works, but suffers from the explosion of punctuation that Perl often gets criticised for. There's an element of Do What I Mean where the first arrow says this is a reference and work the rest out for me.So when you see
$a->[2]{"bar"}
then $a is an array reference where each item is a hashmap. But with $a->[2]->{"bar"}
then $a is an array reference where each item is a reference to a hashmap.Sure you can write amazingly obscure foot-guns in Perl but that's also true of any other language. But honestly I'd rather a few lines of obscure Perl code WITH a comment block explaining why, than a dozen classes with bits and pieces of business logic spread all over the place.
I've done a few small Perl script in the past month, mostly just to try out things and learn a bit more. I'm surprised how robust the code turns out, without me trying. The Perl syntax is a little all over the place at times, but it's incredibly powerful.
Overall it's probably not a language I'd use at work, unless I have to, but for hobby project I would pick Perl again. It has put some of the fun and humanity back in programming.