Used to spend a ton of time writing Perl (see username). Moved on to better designed languages. Which are not hard to find.
There are a few big issues with Perl 5 but the biggest is easily the mess of references vs flat values. Python, Ruby, JavaScript and many other dynamic languages do not make the programmer think about whether you are going to pass a data structure like an array or hash as a reference or direct value. Perl does. A lot of built in operators expect direct values, eg array ops like join, push. This is because the ops existed before Perl added complex data structures — arrays of arrays, hashes of arrays, etc. References were bolted on in Perl 5 to support such structures. And any code using them will handle references not direct values. So you have a split. And then a lot of energy is spent navigating between these two types of variables.
As Steve Yegge said:
“Perl's references are basically pointers. As in, C-style pointers. You know. Addresses. Machine addresses. What in the flip-flop are machine addresses doing in a "very high-level language (VHLL)", might you ask? Well, gosh, what they're doing is taking up about 30% of the space in all Perl documentation worldwide.”
For a taste of this here is how you join an array inside a hash:
join(‘,’,@{$foo->{‘bar’}})
Update - I forgot to say my favorite thing about Perl. The CPAN community. People talk about the sheer scale of CPAN but my favorite thing about it is the quality of documentation, at least back when I was using it. Really good uniform high quality docs. Almost always a great synopsis with multiple good examples covering real uses cases and gotchas. Then thorough documentation of functions/methods. My theory is this culture developed because CPAN predates StackOverflow, github, Google, maybe even search engines. The docs had to be good.
I once did a lot of Perl too, and I agree that Perl has many design flaws, but I prefer it this way. The main reason is if the same array is contained inside two different data structures, I want this to be explicitly obvious in the syntax of the language.
For example:
my $a = [10, 20, 30];
my $b = { array => $a };
my $c = { array => $a };
$b->{array}[0] = 99;
print $c->{array}[0];
To me, anything the syntax can do to make it clear that the above code prints "99" (and not "10") is a net win. I don't care how cluttered it looks or how much extra typing it requires. If a language hides this from me in the name of cleanliness, then it's creating a leaky abstraction that is going to cause bugs and other forms of suffering.
If you're in a language which has immutable arrays, then this doesn't matter. But Perl isn't that, so that's not really relevant here.
To me, languages that add reference types (like C++'s) or language features that allow passing things by reference just create an extra cognitive burden. I look at some code and wonder, "Is this going to have ripple effects in distant places?", and I have to work through some rule in my head such as, if it's an integer, then no, but if it's an array, then yes.
Contrast that with the Perl (or C) way. I look at some code and the syntax tells me. There's no mistaking what's going on. So less cognitive burden and less opportunity for error.
"Python, Ruby, JavaScript and many other dynamic languages do not make the programmer think about whether you are going to pass a data structure like an array or hash as a reference or direct value. Perl does."
If you don't think about these things in python, you're going to be scratching your head when you see something like this:
Since the default is constructed when the function is evaluated, it's the same list, but only when the default is used.
Or the n00b's attempt to use lambdas:
def list_of_lambdas(x):
result = []
for n in range(x):
result.append(lambda m: n + m)
return result
for func in list_of_lambdas(3):
print(func(3))
5
5
5
(All the closures share the same "cell", meaning the same "n", which is 2 at the end of that loop. Worse, if you 'yield lambda ...', that example would look like it worked. So, yes, Python absolutely has references.)
Yes indeed, that's a bug-prone misfeature of Python.
Perl and JavaScript both get default arguments right: They make a new array on each call.
Perl and JavaScript also get the for-loop closures right as well. In Perl, "for (my $n = ...)" and in JavaScript "for (let n = ...)" will both create a new "cell" each time around the loop, so closures work as expected.
(However, MSIE's version of "let" doesn't create a new "cell" each time, and this can be a source of difficult to see event callback bugs; best transpiled out.)
use experimental qw(signatures);
sub plus_one($x = 100) {
return $x + 1;
}
# Says 6.
say plus_one(5);
# Says 101.
say plus_one();
(The subroutine signatures feature is still marked experimental, which is a shame.
I use it in virtually all my code, unless I want pre-5.20 compatibility.)
No, it isn't the same. I'm no language lawyer, but this is my understanding of it.
In python, $foo is a reference. It might be a reference to a scalar value, or list, or hash, etc, but it is a reference. The code you wrote might cause confusion for people who don't understand the python model.
In perl, $foo might be a scalar value, or it might be a reference to a value of some kind. Perl has this exact same type of problem demonstrated by your python code, but in addition it has the problem of "is $foo a scalar value or a reference?"
Imho that's not really correct, or at least misleading.
In Python, variable "foo" behaves like its value is a non-reference if the value is what some languages call "unboxed", for example numbers and strings.
That's exactly the same as Perl.
Technically, Python shares objects even in the case of numbers being copied around, and the object's address is visible with the "id()" function.
(I emphasise address because that was a criticism of Perl in another comment, but everything in Python is memory with an address as well and the criticism ought to apply more strongly because even numbers need memory allocation.)
However, the fact that numbers are immutably-shared when assigned in Python doesn't make their behaviour any different from numbers being assigned in Perl (apart from the obscure id()). It's hard to imagine what "problem" is created in Perl by the fact that numbers and strings are non-references. Most other languages do like Perl.
With strings, Perl does both according to a performance heuristic: Sometimes it copies, sometimes it shares. This is completely safe because you can't tell the difference at language semantics level anyway.
I think OP's point was that even in Python you have to be conscious where your "storage" is--that you're sharing it.
Yes, the "Python" model (or Java, JavaScript) of referring to everything by reference is uniform and simple--except it still shares the issue of having to care if you add mutation into the mix. Due to its apparent smoothness it might even make it easier to run into that. In a sense Perl is honest here in saying I use local arrays via @ prefix and I know this array "lives here", like in the C/C++ world where you have to care about where the storage is so you don't pass references to stack objects etc.; in this world, when you take a reference, it's a heads-up that you may have to care about something. In Perl, unlike in C/C++, you don't have to care about memory safety, but you still, like in all imperative languages, you have to care about sharing of mutations. An explicit reference makes this explicit. If you return an array flat (without taking a reference) in Perl, it is being copied, and while that's slow, it is at least safe. It's an unclean solution for the issue, but in a sense it's at least pointing your head towards the issue.
The clean solution for this is functional programming. Lisp was first to use a uniform "everything is a reference, implicitly" model. But it also preferred a functional programming model where you don't mutate your data structures. Java and Python took the reference model but mixed it with an imperative data update model. Meh.
And I agree that I like the "just use references for everything implicitly" approach. But I also like to combine it with a functional one. And I ended up creating a project to achieve exactly that in Perl, and will shamelessly plug it here: https://metacpan.org/pod/FunctionalPerl (Code written in it co-exists with code that still uses non-reference variables, so feel free to argue that "now you have both worlds mixed", but for one it aims at existing Perl programmers who know how to deal with the non-reference model, and secondly functional programming matters most in the upper levels of an application; it's fine to use imperative code in inner loops / enclosed in an otherwise pure function, and it's fine to use array/hash variables there; FunctionalPerl comes in where you'd traditionally take a reference via `\`; so it's kind of a split between imperative and functional world now).
> The clean solution for this is functional programming
or another model that guarantees that modifications are never seen by code that isn't explicitly meant to receive them--the prominent other model that's making waves nowadays is of course linear types (and extensions as used by Rust).
There are a few big issues with Perl 5 but the biggest is easily the mess of references vs flat values. Python, Ruby, JavaScript and many other dynamic languages do not make the programmer think about whether you are going to pass a data structure like an array or hash as a reference or direct value. Perl does. A lot of built in operators expect direct values, eg array ops like join, push. This is because the ops existed before Perl added complex data structures — arrays of arrays, hashes of arrays, etc. References were bolted on in Perl 5 to support such structures. And any code using them will handle references not direct values. So you have a split. And then a lot of energy is spent navigating between these two types of variables.
As Steve Yegge said:
“Perl's references are basically pointers. As in, C-style pointers. You know. Addresses. Machine addresses. What in the flip-flop are machine addresses doing in a "very high-level language (VHLL)", might you ask? Well, gosh, what they're doing is taking up about 30% of the space in all Perl documentation worldwide.”
https://sites.google.com/site/steveyegge2/ancient-languages-...
For a taste of this here is how you join an array inside a hash:
join(‘,’,@{$foo->{‘bar’}})
Update - I forgot to say my favorite thing about Perl. The CPAN community. People talk about the sheer scale of CPAN but my favorite thing about it is the quality of documentation, at least back when I was using it. Really good uniform high quality docs. Almost always a great synopsis with multiple good examples covering real uses cases and gotchas. Then thorough documentation of functions/methods. My theory is this culture developed because CPAN predates StackOverflow, github, Google, maybe even search engines. The docs had to be good.