Perl suffers from having too many magical operators that makes it hard to reason about a snippet of code.
Certainly a matter of personal preference, but a sprinkling of operators isn't so bad once you're acquainted with the language. Yes it's possible to weave a mess in perl, but most of the time you're just dealing with code that might have a few sigils preceeding an identifier, not ASCII soup.
I'd say the real issue is weak typing (implicit conversions between primitives, using strings for many things where some more specialized data type would have been more appropriate) and variable scope problems. These can lead to hard to locate bugs. Worse is the culture in the perl community of manipulating the VM's internals and generating code at runtime and all kinds of other extremely dynamic behaviors. It's amazing what perl lets you accomplish there, but when some package you got off CPAN does something weird and then something goes wrong, it can get really weird.
Recently I learned that Javascript doesn't handle modulus on a negative number correctly among other things.
That's not really true. Javascript doesn't have a modulus operator, it has a remainder operator, and it is completely valid as a remainder operator. The "%" operator is usually called the modulus operator, but it originated in C where prior to C99 its behavior on signed integers was undefined, and on signed integers modulo and remainder are equivalent. So javascript didn't want undefined behavior so they picked one definition and ran with it, it just so happens that C99 chose the other definition and it stuck.
I'm interested in the details of the variable scoping problems are. I'd have thought that perl's explicit declaration of lexicals with 'my' was better than "declare at first use" of javascript/python/ruby.
[There's a class of mistake where you typo a variable name which you can make in those languages which gets caught in a language where you have to declare variables.]
I share your confusion over that assertion. I actually miss Perl's excellent block scope capabilities when working in almost every other similar language. I imagine most other languages have gotten it, by now, but a few years ago when I was using Python for a few years for a client it didn't have block scope and I missed it. A brief googling actually hints that maybe Python still doesn't have block scope, which is pretty weird, so I assume I'm googling wrong.
But, perhaps discussion of scope problems in Perl is just when talking about very old code. Perl had some scope atrocities back in Perl 4 and some weirdness in early Perl 5 days. But, for the past 15 years or so, it's been very predictable and has improved (like the syntactic sugar of "my" declarations in foreach or while expressions).
I seem to recall that Python not only didn't (doesn't?) have block scope, it tended (tends?) to produce a completely, blithely cryptic error message when the programmer assumes that it does have proper block scope and writes a program that fails as a result. Discovering that was memorable.
One weirdness I encountered recently with nested functions:
sub a {
my $v;
sub b {
# captures only the first
# instance of $v
}
}
This is because named subroutines are created once and variable captures are resolved at that time. I expected the more normal capture semantics you get with anonymous subs, like
sub a {
my $v;
my $b = sub {
# a new $b each time
# captures each $v
}
}
The lexical scoping rules are precisely what causes this behaviour. The first example defines a nested function which has access to the variables in scope when defined (as you remark).
It's little different than this block defined outside of any function:
{
my $v;
sub b { ... }
}
Whereas an anonymous function is "defined" each time the enclosing scope is evaluated.
Thanks - useful point. But, I think that's more of an oddity of nested, named subs than anything else. The usual anonymous subs close as you'd expect (as you say).
> most of the time you're just dealing with code that might have a few sigils preceeding an identifier
I personally like sigils but, afaict, one can almost eliminate sigils in Perl 6 if one wants to.
Instead of $ sigil on scalar (single item) variables:
a scalar =$= 42; # uses a fictional feature [1]
say scalar;
# 42
scalar--; # decrement scalar
scalar.say;
# 41
Instead of % sigil on dicts (hashes):
a dict =%= pi, i, e, now;
say dict;
# 2.71828182845905 => Instant:1435371876.325275,
# 3.14159265358979 => 0+1i
dict<pi>--;
say dict.invert;
# Instant:1435371876.325275 => 2.71828182845905
# -1+1i => 3.14159265358979
Instead of @ on lists (arrays):
a list =@= 10,20;
say list >>+>> scalar;
# 51 61
> I'd say the real issue is weak typing
In Perl 6 everything is (implicitly) nominally typed. One can optionally add explicit nominal type info.
It's certainly not HoTT and it has weaknesses that look unlikely to be addressed this year[2] but it's also one of the most advanced gradual typing implementations in any language.[3]
> implicit conversions between primitives
In Perl 6 conversions are generally explicit. If you name a couple implicit conversions in Perl 5 we could compare with Perl 6 (and, say, Python).
> using strings for many things where some more specialized data type would have been more appropriate
Can you provide an example?
> variable scope problems.
Scope features are very much a Perl 6 strength.
Again, perhaps describe a scenario where it's a weakness in Perl 5 and we can compare with Perl 6 and perhaps other langs?
> manipulating the VM's internals
The "reference" Rakudo Perl 6 compiler is a front-end to the NQP compiler toolchain. The NQP toolchain targets several VMs including the JVM. It does not manipulate the JVM's internals!
(NQP also targets MoarVM[4] but it uses the same principled ways to communicate with MoarVM that it does with the JVM.)
> and generating code at runtime and all kinds of other extremely dynamic behaviors.
Ah yes. Perl 6 has upped the ante on that. It is statically compiled in a lot of ways but it also has very powerful dynamic features, carefully designed. [5]
----
[1] I made up the term 'a'. In reality it's 'constant'. But that name is kinda surprising for the purposes to which I've put it -- the terms it declares aren't very constant! But 'constant' is much longer than 'a' and this sort of declaration is supposed to be harder than using other scopes such as 'my' or 'has'. See http://irclog.perlgeek.de/perl6/2015-06-27#i_10812609 and following for a tiny bit more discussion.
Certainly a matter of personal preference, but a sprinkling of operators isn't so bad once you're acquainted with the language. Yes it's possible to weave a mess in perl, but most of the time you're just dealing with code that might have a few sigils preceeding an identifier, not ASCII soup.
I'd say the real issue is weak typing (implicit conversions between primitives, using strings for many things where some more specialized data type would have been more appropriate) and variable scope problems. These can lead to hard to locate bugs. Worse is the culture in the perl community of manipulating the VM's internals and generating code at runtime and all kinds of other extremely dynamic behaviors. It's amazing what perl lets you accomplish there, but when some package you got off CPAN does something weird and then something goes wrong, it can get really weird.
Recently I learned that Javascript doesn't handle modulus on a negative number correctly among other things.
That's not really true. Javascript doesn't have a modulus operator, it has a remainder operator, and it is completely valid as a remainder operator. The "%" operator is usually called the modulus operator, but it originated in C where prior to C99 its behavior on signed integers was undefined, and on signed integers modulo and remainder are equivalent. So javascript didn't want undefined behavior so they picked one definition and ran with it, it just so happens that C99 chose the other definition and it stuck.