2007-06-03

Classy

Let's talk about classes for a minute.

Classes are nature's way of saying "your program is too complicated". Programmers love classes because they're the only thing the best minds in the field of computer language design have developed to handle something called "objects". Programmers love objects because it helps them do something called "object-oriented programming", which everybody has to put on their resumes in order to get interviews, whether they actually use it or not.

Object-oriented programming, to put it bluntly, is a method in which you make your program bigger, slower, and more complicated in order for a few developers to gain the advantage of "understanding it better". This is something that programmers bandy around because it sounds better than "we're lazy". Several perfectly usable languages don't make use of objects and no one seems to mind too terribly much, and C programmers really don't spend a lot of time bitching about how much better it would be if only they could use a class.

I personally don't like to use classes if I don't have to, simply because they're so much overhead in a program that it's usually easier to write a smaller program that does a more specific job. Also, I'd probably kill myself before writing something that generically inherits stuff from something else.

From time to time, usually after my arm has been twisted or because they're paying me, I will write an object or two. This is, unilaterally, a painful process that ends with some code that is not significantly more readable or more maintainable than non-OO code. The only difference is that afterwards I'll usually end up dropping a few tabs of prescription opiates into my glass of bourbon to watch them fizz like Alka-Seltzer.

Take Perl for instance. Perl is a language specifically designed to let you do whatever you feel like doing however you might happen to feel like doing it that day. It predates the whole object-oriented craze, and thus its object-oriented support is kind of bolted on in a style similar to how object-oriented ideologies were bolted onto the programming languages of yesteryear. They changed the terminology and created a work alike method in which you can use the existing Perl syntax to build something that looks and tastes almost, but not entirely, unlike a class.

This isn't a slam against Perl so much as it is an illustration of the flexibility of the language. If you can take something and make it into an object-capable version of itself, wow. Just wow. I guess it goes to show that things aren't inherently good or evil; it's what you do with them that counts.

So the bullets are out of the gun: Perl does OO and there's nothing we can do about it. The problem is that when you sit down and say "I'm going to use Perl to write up a bitchin' class," you're in for a world of pain. Perl was, literally and figuratively, not designed for this sort of thing. So to provide it, there are certain hoops that must be jumped through and hassles that must be endured. Let's have an example. Classes are a good way to compartmentalize information, so a programmer can say "I want to create an object that has the properties of a human being", and then be able to group those properties into a single data structure.

Here's a basic class structure in Perl:

package Human
  sub new {
    my $proto = shift;
    my $class = ref($proto) || $proto;
    my $self = {};
    $self->{age} = undef;
    $self->{name} = undef;
    bless($self, $class);
    return $self;
  }
1;

God only knows what all this jazz is. Reading the Perl docs shows you the Perl-based parallels: "A class is a package, a method is a subroutine". As far as these things go, I say if it looks like a duck, if it walks like a duck, and if it gives you a reference to a dynamic self-contained data structure like a duck, it's a duck. I won't fault Perl too badly for having a "we've got that too" attitude, but I would like to illustrate that it hurts the language by making it a hassle to get what newer languages already have built into them.

In the above Human class, for example, we have a couple of interesting properties of a person: an age and a name. We could easily make a new Human variable in Perl now by including the Human package and calling the new method:

my $person = new Human;

Great! We've got a working class. There's just one problem: we have no way to get data into or out of our nice new object. Inside the Human class, we've only specified one method, new. There's no way to get at any of the gooey goodness that exists inside the hash reference Human calls "self". So our basic class structure is incomplete without accessor methods for our data. Let's add those, then.

sub age {
  my $self = shift;
  $self->{age} = shift if (@_);
  return $self->{age};
}

sub name {
  my $self = shift;
  $self->{name} = shift if (@_);
  return $self->{name};
}

Do we need to have one of these subroutines for every single variable our class will have? Yeah, pretty much. Is it a huge pain in the ass? Yeah, pretty much. Is it a big indication of how not-really-designed-for-OO Perl is?

Yeah, pretty much.

Perl's come up with a few ways to get around this suckage, primarily through add-on modules like Class::Struct, or Class::MethodMaker, which lets you trade off complex class-making code for a new syntax (and the prayer that all your deployed platforms will have that module when you run your own code).

A new approach to Perl's philosophy came along in the form of Ruby, a language similar enough to be mentioned in the same breath, but different enough to warrant having to buy a whole new set of O'Reilly books on the subject. Ruby's big marketing push is that "absolutely everything and his brother is an object", making it even more Java-ier than Java is. This is a good selling point for proponents of OO and largely irrelevant to everyone who couldn't care less. Ruby aficionados point out that you can call methods on literals like the number 5 or the string "Hi mom". Whatever. Right now we only care about how painful it is to build a class.

In much the same way that the Be operating system was "pervasively multithreaded", the Ruby architecture is "pervasively object-oriented". You really can't help but use classes even if you hate them. One would hope that constructing a new class would be relatively easy considering how loudly Ruby proclaims to love objects. Our Human class in Ruby would look a bit like this:

class Human
  attr_accessor :age, :name
end

What? Did I miss a section?

No, no I didn't.

Given that three-line snippet, it's pretty clear to even the casual reader that Ruby's class-building approach is so many orders of magnitude better than Perl's that I flat-out want to have sex with it. Granted, Ruby's innards are remarkably sophisticated and I haven't even begun to discuss any practical OO designs, so I trust that you can take this example to see how much heavy lifting Ruby does for you, and why developers who have a hard-on for writing classes are starting to flock to it in droves.

I find Ruby to be remarkably faster than Perl in many regards, but not significantly easier to use when not explicitly utilizing objects. Perl's strengths lie in slicing and dicing strings and regexes, not in abstracting your data into a class. I wouldn't want to write a parser in Ruby, and I wouldn't want to write an object in Perl. Other differences aside, Perl stands to lose a huge amount of support to whippersnappers that make building classes easier. I haven't had the stomach to follow Perl 6's development, but I'm fairly certain it shall come too late to retain Perl 5's userbase or woo back any early adopters of these newfangled languages that don't act like they hate their developers.

Next time: why I didn't even mention Python.

No comments: