With PHP, Python, Ruby and Javascript... space seems tight for another scripting language. Languages like Lua have something special. What's special about Perl?
Edit: I don't want to be hateful. The more the merrier obviously.
With PHP, Python, Ruby and Javascript... space seems tight for another scripting language. Languages like Lua have something special. What's special about Perl?
Edit: I don't want to be hateful. The more the merrier obviously.
The original killer feature of Perl was regexs - these existed before, but Perl's implementation destroyed all others, and 'PCRE' (Perl compatible regular expressions) became the default - most modern languages use PCREs for their regexs.
There was some bad stuff that happened with this too - people used regexs for ghetto, half-assed versions of tree structures like HTML and XML - but for the task of chewing through Unix config files, up until around 2005 Perl was unbeatable because of the awesome regex support (and because it's history meant, at the time, perl was installed on all Unix boxes).
Also a note about the sigil: Get a decent syntax highlighting set up for your editor and you'll quickly realize how nice it is to have functions, variables and different variable types colored differently.
print x if x > 5
is problematic in p5 for a whole bunch of reasons:(1) At a bare minimum, what you really need to say is:
print "$x\n" if $x > 5;
That extra "\n" is a definite turn-off to a lot of people when the get their very first look at Perl. Really, the default these days should be more "say"-like. Of course, "say" is there as of 5.10 if you know where to look for it, and you go out of your way to enable it: use feature 'say';
say $x if $x > 5;
(2) In "modern", better practice, production-quality Perl you pretty much have to either hedge every comparison op with a check for defined-ness: use feature 'say';
say $x if defined $x && $x > 5;
in order to head off an unsightly warning about $x not being initialized: Use of uninitialized value $x in numeric gt (>) at print-if.pl line 5.
or add even more boilerplate to suppress the warning: use feature 'say';
{
no warnings 'uninitialized';
print $x if $x > 5;
}
or be very attentive about how $x can mutate once it's gotten passed whatever validations you're imposing on it before it enters your scope -- via e.g. Params::Validate, Method::Signatures, provided you know these tools exist and are up to speed and hip as to how to use them effectively.(Yes, I know that in some contexts, the warning on 'uninitialized' can be very useful. But my point is, most of the time, and especially for novices, it's more of a misfeature).
(3) We shouldn't gloss over the fact that the magical pseudo-grammatical construction the "infix" if syntax provides is itself problematic in many ways.
In the current example, it simply isn't clear -- until you've become very comfortable with the language! -- if the original statement
say $x if $x > 5;
is or is not equivalent to the very similar construction $foo = $x if $x > 5;
say $foo
This is because it is by no means obvious as to which of the more "active" parts of the original expression -- either the "verb" (print) or the conditional (if) -- takes precedence.And unfortunately, it's not only possible, but terribly easy to "whip up" fare more volatile constructions like this in Perl 5. Various on this theme -- gotchas about print, conditionals, and complex "if/unless" constructions -- were of course given ample treatment in Perl Better Practices, to the point where (I believe) that Damian pretty much eschews "trailing" if/unless constructions altogether.
(4) Lastly, it's sad to say that for all the complains of Python having too many safety belts and what not, it completely nails the hidden complexity management issues embedded in such a simple construct like Perl's "print-if" idiom.
In Python, basically the only sensible way to achieve the original desired result is to do this:
if x > 5:
print x
Perfectly clear, completely unambiguous, and basically impossible to screw up.Isn't it? If someone told you, really you to do just that, would you actually have a problem carrying out that command given a way to print something, a container, and a value to check against the container contents?
Also, here's me preference:
say $x if $x and $x > 5;
Need to catch zero? say $x if defined $x and $x == 0; for my $item ( @items ) {
# Weed out the things we don't want to process
next unless $item;
next unless $item->{foo} < 3;
next if $item->{bar} < 2 and $item->{baz} =~ /quux/i;
# Yep, these are good for processing
$item->{othername} //= "$item->{foo} - $item->{baz}";
process( $item );
}
Could that be done using maps and greps, and even be faster? Sure. Would it be harder to reason about and add documentation to? Probably.Additionally, I use them for parameter verification in subs:
sub foo {
my ($cowbell,%attrs) = @_;
die "Needs moar cowbell!" unless $cowbell;
die "Invalid color!" unless $attrs{color}//'' =~ /\A(bronze|silver)\Z/i;
# blah
}
P.S. That's not to say I don't love a good map and grep combo, I do. After a certain point of craziness I convert to a loop and document a bit. I tried to add enough items to the loop that it would be a cumbersome map and grep.The problem here is that's just one way (in linguistics: "voice") in which the statement can be parsed. Another way is to look at it mathematically:
print <expr>
where expr := x if x > 5
which of course has an entirely different meaning.What compounds the difficulty is that in general it's really difficult to anticipate all of these syntactical corner cases through a careful, a priori study of the man pages, or any of the available introductory literature. The only time-effective way (for most people) to get up to speed in a new language is through practice. Supplemented of course through book & occasional man page study. But really the way most people learn is programming is "by doing."
Which, sadly for Perl 5, means "by shooting yourself in the foot", in the prolonged early learning phase, for most people.
Statement Modifiers
Any simple statement may optionally be followed by a SINGLE modifier, just before the terminating semicolon (or block ending). The possible modifiers are:
if EXPR
unless EXPR
while EXPR
until EXPR
when EXPR
for LIST
foreach LIST
There are rules for how loosely and tightly different operators bind. Read the docs, and your questions will be answered. Ignoring the documentation does not make for a good argument.This has been observed with countless other technologies -- JavaScript, MySQL, MongoDB, etc. Long-time Perl hackers tend to forget their first experiences with the languages (which for many with languages with far worse track records on the consistency / simplicity scale). But newer users have (rightfully) come to expect much better.
And interestingly: the very use case that started this whole thread
statement IF
isn't in your excerpt, above. Which means that new users are most likely to encounter it "experimentally", i.e. while debugging someone else's convoluted while/unless/last/goto loop.Of course, it's not that hard to "figure out." Implicitly, it refers to the issue of precedence, which is presumably detailed, uh, somewhere else. Which means a new user to the language has to either spend more pillow time reading, or more hair-pulling time watching their programs blow up unexpectantly before they "get the hang of it."
Which has a lot to do with why newer programmers just aren't turning to Perl as much, these days.
The point is that in any well designed product you shouldn't have to study the docs (all that much) in order to start being productive
And I don't think you need to in order to assume the correct functioning of
print $x if $x;
As much as you may find it compelling to point towards it's possible interpretation as print( $x if $x );
I find that interpretation nonsensical, and anyone making any effort to learn how the language works or if not that, at least think about what it could mean and what it probably means will not be surprised. Perl tries to Do The Right Thing (DTRT) whenever possible, and with this principle in play, I think the meaning of this statement is very obvious.Even if we extend the statement to be somewhat more ambiguous, a bit of thinking about the problem makes it obvious what the right thing to do is, and it is indeed what Perl does:
print $x, $y if $x;
# OR
print $x, $y if $y
You can either interpret that as Perl does, or as: print( ($x), ($y if $x) );
# OR
print( ($x), ($y if $y) );
Do you ever really want something like that? Is that useful to you, given that there are a few other ways of achieving that which are much less cumbersome ($y||$y)?The point is that in any well designed product you shouldn't have to study the docs (all that much) in order to start being productive. And there should be as few "gotchas" as humanely possible please. Did I say pretty please?
It's almost comical that you are making this argument. One of Perl's strong points is that it's really easy for someone to pick up and start using, because it tries to DTRT, making it very easy for the beginner.
Long-time Perl hackers tend to forget their first experiences with the languages (which for many with languages with far worse track records on the consistency / simplicity scale). But newer users have (rightfully) come to expect much better.
When I mention Perl, I still hear people immediately jump out with "Oh, I remember I used Perl back in the day and it was real easy to whip up a little program to do what I wanted."
I think what you are running into is that you have experience and expectations with other languages, and when Perl doesn't match those expectations, you blame Perl, rather than meeting it at it's own level. I suspect you don't do this as much with languages that appear radically different, such as Haskell and Lisp. If so, is that Perl's fault for following a different path, or yours for failing to use it appropriately?
say $x if defined $x and $x == 0;
Ya know, it'd be nicer if Perl 5 just had more sensible semantics to this whole "undef" business. For one thing, it's inherently confusing to conflate the semantics of "none of the above" with "not yet scoped". These are two entirely different states of being, yet this is exactly what Perl 5 does.Really, something like None (as in Python), or Nil as in Perl 6 works a whole lot better. And whatever your magical "none of the above" symbol is called, it really should be == to anything else besides itself. Don't know about you, but
$x = undef;
print "boo!\n" if $x == 0;
# boo!
smells way too much like PHP for my tastes.Granted, Perl 5 was truly revolutionary in its time, and provided way better semantics for this particular corner case than any of its contemporaries. But it's 2013 and sadly, we know a whole lot better now.
Now, as to the fact that sigils basically don't bring all that much to Perl, are weird and distracting to newcomers and at the end of the day create as many problems as they solve... let's not go there, for now.
I don't develop on Windows or Mac, since I work on server-side software, so I might just be blissfully ignorant of a serious problem.
The documentation for those was poor. I remember the documentation for Moose being poor, as well as the documentation for Catalyst being especially bad.
And that's not even talking about the built-in documentation. Even in 1994-5 when I first learned Perl, I learned it completely from the Perl man pages and not from a book. The man pages are comprehensive, easy to read, and organized well for reference.
Ruby, Python, PHP and Node really need to get their act together and follow Perl's lead in this area.
Its true. Perl feels like a very powerful base language, moving to Python felt like you were taking a bit away (I know in reality you can probably achieve much the same things). Python on the other hand doesn't require you to implement your own basic functions (max, min , trim / strip ) as they are included already. Python stops me from shooting myself in the foot as often, by not allowing me to do stuff that is too clever too early.
I do miss being able to reference / deference variables explicitly though. Other great things are, CPAN, regular expression support (that never feels as nice in Python), one liners for doing stuff quickly on the command line. I even quite like the sigils, as an easy way to recognize the types of variable you are dealing with (though it is confusing at first). Working with strings feels a lot more natural in Perl than Python.
Or even better, just use List::AllUtils - https://metacpan.org/pod/List::AllUtils
Perl has a minimal std library, to teach people to use CPAN I guess. But even Perl has util modules for trivial help functions in the std install (at least those which aren't one line of code to define).
The strongest argument for Perl today is CPAN and CPAN Testers, still the gold standard.
But all the scripting languages are really similar, there is no reason to learn another if you already know one.
Edit: You might want to check out the Modern Perl book, free online. Perl evolves quite fast.
But Perl-like ambiguity still seeps into your English. Was that Python 3, or 3 years ago?
(Ok, I just checked, Python 3 has been around longer than I thought).
I'm not trying to dump on perl. I love C and C++ and those get dumped on all the time and I hate it. But anything I could do in Perl I instead do in Ruby. It's not as fast, but if fast matters I'm not supposed to use a scripting language.
Perl can actually be very fast; it depends on what you're doing and how you write it. A lot of developers don't realize that Perl isn't really a scripting language; it's a compiled language that has a compiler that's so fast it can be run every time you run the program. The compiler produces bytecode, and the bytecode runs on a virtual machine, just like Java and C#.
The key to writing fast Perl code is to use programming constructs that compile down to single bytecode operations, because those operations are implemented in the VM using well-tuned C code. For example, using grep and map with array variables is much faster than using a for loop and explicitly indexing through the array. With the former, the enumeration is handled in C code, while in the latter it's handled in Perl code.
Note: that's probably not 100% accurate, but it's the general idea. You can actually have perl output the bytecode it generates so you can take a look at it, and figure out places where changing how your code is structured will produce more efficient bytecode.
I started using Perl on VMS, where there was no sed, (g)awk was new, no grep ("search" did not handle regular expressions, "find" did but arrived very late); and the command language, while sane, was very slow. Perl's system integration on VMS was excellent.
That's an ironic statement, since Perl came first and was absolutely dominant in the domains which PHP, Python, Ruby, and Javascript now occupy. When they were young, it would have been reasonable to say that space seems tight for another scripting language because we had Perl.
Languages like Lua have something special. What's special about Perl?
What's special about Lua? That's a four-word question that could require a huge response. Lua's a nice little embeddable scripting language, but that's a niche that Perl has occupied too. It's got fantastic support for both being embedded (callable from other languages) and embedding (able to call other languages). You might say that Lua's better because it's smaller and cleaner and simpler, but that's only true until you run into Lua not being powerful enough for something you want to do. If you used Perl as your embedded scripting language instead, you probably wouldn't have that problem. (Other problems, maybe, but not a lack of power.)