I just watched a CCC talk in which the speaker claims Perl is horribly broken. Watching it was fairly annoying however, since I had to restrain myself from throwing things at the screen.
If you're going to complain about the language, better make sure you actually understand the language first. I won't deny that there are a few weird constructions in there, but hey. The talk boils down to a claim that perl is horrible, because the list "data type" is "broken".
First of all, Netanel, in Perl, lists are not arrays. Yes, that's confusing if you haven't done more than a few hours of Perl, but hear me out. In Perl, a list is an enumeration of values. A variable with an '@' sigil is an array; a construct consisting of an opening bracket ('(') followed by a number of comma- or arrow-separated values (',' or '=>'), followed by a closing bracket, is a list. Whenever you assign more than one value to an array or a hash, you need to use a list to enumerate the values. Subroutines in perl also use lists as arguments or return values. Yes, that last bit may have been a mistake.
Perl has a concept of "scalar context" and "list context". A scalar context is what a sub is in when you assign the return value of your sub to a scalar; a list context is when you assign the return value of your sub to an array or a hash, or when you use the list construct (the thing with brackets and commas) with sub calls (instead of hardcoded values or variables) as the individual values. This works as follows:
sub magic {
if (wantarray()) {
print "You're asking for a list!";
return ('a', 'b', 'c');
} else {
print "You're asking for a scalar!";
return 'a';
}
}
print ("list: ", magic(), "\n");
print "scalar: " . magic() . "\n";
The above example will produce the following output:
You're asking for a list!
list: abc
You're asking for a scalar!
scalar: a
What happens here? The first print
line creates a list (because things
are separated by commas); the second one does not (the '.' is perl's
string concatenation operator; as you can only concatenate scalars, the
result is that you call the magic() sub in scalar context).
Yes, seen as how arrays are not lists, the name of the wantarray() sub is horribly chosen. Anyway.
It is documented that lists cannot be nested. Lists can only be one-dimensional constructs. If you create a list, and add another list as an element (or something that can be converted to a list, like an array or a hash), then the result is that you get a flattened list. If you don't want a flattened list, you need to use a reference instead. A reference is a scalar value that, very much like a pointer in C, contains a reference to another variable. This other variable can be an array, a hash, or a scalar. But it cannot be a list, because it must be a variable -- and lists cannot be variables.
If you need to create multi-dimensional constructs, you need to use references. Taking a reference is done by prepending a backslash to whatever it is you're trying to take a reference of; or, in the case of arrays of hashes, one can create an anonymous array or hash with [] resp {}. E.g., if you want to add a non-flattened array to a list, you instead create a reference to an array, like so:
$arrayref = [ 'this', 'is', 'an', 'anonymous', 'array'];
you can now create a multi-dimensional construct:
@multiarray = ('elem1', $arrayref);
Or you can do that in one go:
@multiarray = ('elem1', [ 'this', 'is', 'an', 'anonymous', 'array']);
Alternatively, you can create a non-anonymous array first:
@onedimarray = ('this', 'is', 'not', 'an', 'anonymous', 'array');
@multiarray = ('elem1', \@onedimarray);
In perl, curly brackets can be used to create a reference to anonymous hashes, whereas square brackets can be used to create a reference to anonymous arrays. This is all a basic part of the language; if you don't understand that, you simply don't understand Perl. In other words, whenever you see someone doing this:
%hash = {'a' => 'b'};
or
@array = [ '1', '2' ];
you can say that they don't understand the language. For reference, the
assignment to %hash
will result in an (unusable) hash with a single
key that is a reference to an anonymous hash (which cannot be accessed
anymore) and a value of undef
; the assignment to @array
will result
in a two-dimensional array with one element in the first dimension, and
two elements in the second.
The CGI.pm fix which Natanel dismisses in the Q&A part of the talk as a "warning" which won't help (because it would be too late) is actually a proper fix, which should warn people in all cases. That is, if you do this:
%hash = { 'name' => $name, 'password' => $cgi->param('password') };
then CGI.pm's param()
sub will notice that it's being called in list
context, and issue a warning -- regardless of whether the user is
passing one or two password
query-parameters. It uses the wantarray()
sub, and produces a warning if that returns true.
In short, Perl is not the horribly broken construct that Natanel claims it to be. Yes, there are a few surprises (most of which exist for historical reasons), and yes, those should be fixed. This is why the Perl community has redone much of perl for Perl 6. But the fact that there are a few surprises doesn't mean the whole language is broken. There are surprises in most languages; that is a fact of life.
Yes, the difference between arrays and hashes on the one hand, and lists on the other hand, is fairly confusing; it took me a while to understand this. But once you get the hang of it, it's not all that difficult. And then these two issues that Natanel found (which I suppose could be described as bugs in the core modules) aren't all that surprising anymore.
So, in short:
- Don't stop using Perl. However, do make sure that whenever you use a language, you understand the language, first, so you don't get bitten by its historical baggage. This is true for any language, not just Perl.
- Don't assume that just because you found issues with core modules, the whole language is suddenly broken.
What I do agree with is that if you want to use a language, you should understand its features. Unfortunately, this single line in the final slide of Natanel's talk is just about the only thing in the whole talk that sortof made sense to me.
Ah well.
I also blogged about this.
Another aspect is, that the vulnerable is not a perl problem. The Bugzilla programmers didn't check an input from the outside and I wrote all my perl scripts "warning free", if you do this you have to write:
%hash = { 'name' => $name, 'password' => $cgi->param('password') || '' };
otherwise you'll get a warning if the script don't receive a 'password' parameter.
I hope Netanel only use languages which never had any vulnerable and where never any programmer did programm a security hole.