I’ve complained for years that Perl is excessively idiomatic, and I normally get the response back either a) that the idioms just help you shorten your code, or b) that all languages have idioms, and there’s nothing particularly odd about Perl in that regard.
I think we can accept the truth of both those assertions, yet agree that use English is a good addition — e.g., $EUID to get the user’s current effective UID rather than $<.
I think we can also agree that local variables in Perl are just nasty. They are something like a global, something like a local variable. Mark-Jason Dominus does another one of his well-written Perl exposés to show us what it’s all about, and still I had to stare off into space and ask myself, “Can you really explain the difference between my and local?” I sort of can: you use local when you want to use a global variable with a temporary local value. But then you shouldn’t be using global variables, so the number of cases where you’d do this is fairly limited. In fact it looks like the special Perl punctuation variables (like $/, also known as $INPUTRECORDSEPARATOR) can in many cases not be given lexical scope via my, which means you need to use local to override their global values in particular places.
I’m not yet enough of a Perl wizard to understand the symbol table, and typeglobs and so forth. Understanding this stuff is in fact quite useful, and Dominus uses it to good effect in his Memoize module. Memoize will make a cached version of any function name you give it, and will rewrite the global symbol table so that when you call foo() it’s actually calling the memoized version of foo(). That seems pretty hot.
Anyway, I am perhaps denying myself some efficiency by avoiding local altogether. Dominus makes some light fun of those who use FileHandle to get a handle with lexical scope rather than writing a one- or two-line typeglob hack to accomplish the same thing. Me, I prefer the mindless solution: use FileHandle, and you know that you will never ever have to think of any weird namespace collisions. It Just Works.
P.S.: Reading further on that page, I discovered at least one interesting thing: Perl prototypes are not quite the same beast as C++ prototypes. Actually I didn’t even know about Perl prototypes at all until earlier today, and then I thought they were a Perl 6 development. But it turns out that if you do something like
sub arraysAreSameLen(\@\@);
and then later on actually assign some content to arraysAreSameLen(), the Perl compiler will do some more checking for you: it will expect that arraysAreSameLen() takes two arrays as arguments. It’s a teensy bit magical, too: the \@ syntax is Perl-speak for “reference to an array”, which is well-chosen notation, because what the compiler is actually doing is turning the arguments that you pass to arraysAreSameLen() into array references. I.e., anyone calling into arraysAreSameLen() would just do
arraysAreSameLen( @array1, @array2 );
when in fact arraysAreSameLen() would have to do something like this in the backend:
sub arraysAreSameLen( \@\@ ) { my @array1 = @{$[0]}; my @array2 = @{$[1]}; }
If you then were to call arraysAreSameLen(@array1), you’d get a syntax error:
(22:05) slaniel@TheloniousMonk:~$ bin/prototest.pl Not enough arguments for main::arraysAreSameLen at bin/prototest.pl line 10, near “@list1)” Execution of bin/proto_test.pl aborted due to compilation errors.
Which is to say that this compiler instruction
adds one more level of safety to your code, of the sort that you’d get from use warnings and use strict;
and it also
helps out your callers a little bit: you handle a bit more of the messiness, by handling referencing and dereferencing objects; they only have to worry about passing you blue-blooded, wholesome, god-fearing objects.
I’m not sure whether Perl prototypes are like their C counterparts, where you can either do
int funcName( char* varName1, int varName2 );
or just
int funcName( char*, int );
It would be nice if they were; I look for any opportunity to make Perl more literate.
This is all rather more exciting to me than it ought to be. Earlier this week I found some Perl module — I can’t find it just now — that lets you build in some argument checks, and I was all psyched to start using it. But if the compiler itself won’t even let your program run when the argument list isn’t right, then that’s obviously much better.
The next step is to use named arguments like Python uses. One gets this a bit in Perl by using hash arguments, à la
funcName( { arg1 => val1, arg2 => val2, } );
which is cool. But it would be nice to have built-in support for it.
P.P.S.: The next next step would be to allow higher-order syntax checks at the compiler. E.g., I want to ensure that arguments which are supposed to be probabilities are really between 0 and 1; is there any way to force the compiler to die if this condition isn’t satisfied?
I suppose the right way to do this is to create a probability class, which throws an exception or something if it’s not initialized properly. But I wonder if there’s any way to catch the error earlier than an exception — in Perl or in any other language.