Criticizing Perl

Ovid on 2005-10-05T17:53:19

I love the Perl language. Unfortunately, there's quite a bit to criticize about it. Most of the issues which dissatisfy me are being fixed in Perl 6, but that's a long way off. So for the time being, I work around the problems.

There are two major camps of those who criticize Perl: those who know the language well and those who know the language poorly. Their criticisms do not generally overlap. It's gotten to the point where when someone says "I don't like Perl", I usually say "many people don't" because most people who don't like Perl don't know much about the language and didn't bother to learn. They see sigils on the front of variables and say the language looks like line noise. They see examples of Perl from bad programmers and generalize that to all of Perl. They "know" that only strongly typed (whatever the hell that is) languages are worth considering so Perl "must be bad".

Anyone whose thought processes are that simple-minded is someone I don't want working for me. There are plenty of reasons to dislike Perl. The three aforementioned ones aren't in that list.

One issue which amuses me the most, though, is how some people think Perl is so bad but keep mum on the subject of PHP. Most folks with only a passing familiarity of either language would be hard-pressed to tell them apart.

I wonder, though, if part of the problem lies in Perl's power? To really exploit the full richness of the language, you have to know it well. How many will stick with it long enough to get there?


tease

phillup on 2005-10-05T18:45:56

Unfortunately, there's quite a bit to criticize about it.

You are such a tease!

I myself don't really have a lot of complaints about the language, except that it sure would be nice to have a spiffy IDE sometimes... and it mostly doesn't because it is so dynamic as to make that difficult.

But, I am interested in hearing what you *would* consider a "legitimate" complaint. (Would I be correct in assuming most lie in the OO area?)

Re:tease

Dom2 on 2005-10-05T19:37:09

There are plenty of valid complaints about Perl. You're right, a lot are in the OO department (how may ways are there to define a class?) But there's also the slew of weirdly named globals. And the lack of proper named parameters. I think inconsistency is probably one of the biggies too (how many global variables do you need for error handling?) Like you say, Perl 6 will (eventually) rectify a lot of these. Or you can look at Ruby today to get some of them fixed. ;-)

As to an IDE, probably the best that you'll get is something like EPIC. But an IDE for Perl 5 will never be that good because of the language. Perl is so dynamic, that it's nigh on impossible for an IDE to tell you what methods are available (because there are so many ways to define a class) and what parameters they take (because there is no standard way to do named parameters). So you see your desires for the spiffy IDE are related to language misfeatures.

-Dom

Re:tease

Ovid on 2005-10-05T20:08:49

In addition to Dom's comments, I would also add a complaint that, ironically, I also have with Java: mixing objects and primitives (Perl's less of a pain, but still a pain).

Lately I've been thinking a lot about allomorphism (think "duck typing" in Ruby) and how it relates to programming. Consider the following snippet:

foreach my $method (@methods) {
  foreach my $object (@objects) {
    next unless $object->can($method);
    $object->$method( $args_for{$method} );
  }
}

That's powerful. Dangerous, but powerful. Many languages would force you to jump through a lot of hoops to replicate this behavior (if it's even possible).

Where does @objects come from, though? If the programmer supplies them, what happens when she does this?

process($object1, $object2, [ qw/foo bar baz/ ]);

The call to $object->can blows up. There's no reason it has to but now we're forced to rewrite our code to do something like this:

use Scalar::Util 'blessed';

foreach my $method (@methods) {
  foreach my $object (@objects) {
    next unless blessed $object && $object->can($method);
    $object->$method( $args_for{$method} );
  }
}

That seems like a contrived example, but I've found this biting me more than once. Here's an example I recently had to write.

sub _attributes {
    my ( $self, $attrs ) = @_;
    return '' unless $attrs;
    if ( ref $attrs && UNIVERSAL::isa( $attrs, 'SCALAR' ) ) {
        return ' ' . $$attrs;
    }
    my @attributes = UNIVERSAL::isa( $attrs, 'HASH' ) ? %$attrs : @$attrs;
    return '' unless @attributes;
    # more code here
}

Because it's the person using this module who controls what is getting passed in (from a function at a higher level, not this one directly), I've no control over whether or not they're passing in a normal reference. As a rule of thumb, having to check isa() indicates a design flaw. Theoretically, I should just be able to do something like this:

sub _attributes {
  my ($self, $attrs) = @_;

  # the following line is for illustration purposes only.  The
  # higher level code would probably call this method directly
  return $attrs->_build_attributes;
}

I could do that now, but that means blessing the references passed in and that means that I've modified the calling variables and that's bad. Of course, I could clone them and then bless them, but that gets annoying, too. Instead, I'd like to be able to have a _build_attributes method exist internally for scalar, array, and hash references and only make it visible to trusted classes. That would simplify the logic quite a bit and allow Perl to handle dispatching rather than the programmer handling dispatching.

There are also some annoying bugs with typeglobs. One irritation occurs when one has a CODE slot defined in a glob with no corresponding subroutine. This breaks inheritance and causes weird "not a code reference" messages. Unfortunately, the best fix seems to either be deleting the entire glob or create a subroutine which dispatches up the inheritance heirarchy or dies with a "no such method" error message :(

Fortunately, I think all of these complaints go away in Perl 6. Not sure about trusted methods, though.

Re:tease

runrig on 2005-10-05T22:28:43

As a rule of thumb, having to check isa() indicates a design flaw.

There is Scalar::Util::reftype(), which would make the code slightly less ugly and broken, but your theoretical alternative would be nice also.