|Perl: the Markov chain saw|
Abstract Classesby hardburn (Abbot)
|on Apr 28, 2003 at 15:18 UTC||Need Help??|
Probably the only thing that annoys me about Perl5's object system is doing inheiratence, especially abstract classes. To those not familer with OO-jargon, an abstract class is where the methods of a class are defined but not implemented. A subclass is required to implement each method in its abstract parent class. This has been discusssed previously in Interfaces in Perl?, but I'd like to revisit the issue.
For instance, we might have an Animal class that defines methods like move(), eat(), and drink(). However, animals have a huge number of different ways to move around, eat, and to drink. Some might move via fins, others with legs, and some with wings. Our Animal class would only define that all animals must have some means of moving around, eating, and drinking without specifiying how these tasks are accomplished.
IMHO, there are two requirements for an object system to do abstract classes well:
I hold little hope for doing #2 in Perl5. It requires a way to define what types of variables are allowed to be passed in. While Apocolypse 6 defines ways to do this in Perl6, that won't be of help to us in the near future. While Perl5 has a prototyping system, it isn't meant to be used for this task and is of little benifit. The only means to accomplish #2 is to have a community agreement to implement subclassed methods in a certain way. Embedding it in the language avoids mistakes and increases the code's self-documentation.
#1 might still be possible. This means either doing compile-time enforcement of abstract classes, or checking the existance of each method at run-time and dieing if a subclass doesn't implement it. Intuitively, compile-time enforcement is more efficent.
Some solutions out there right now:
Define abstract methods to die() on being called
This is the most common method I've seen. Its main problem is that a method which was never implemented in a subclass will still work as long as that method is never called. Theoretically, a mis-implemented subclass could be used for years if a little-used method is never called.
Its syntax is nicer than the die(), but is implemented internally the same way, and thus has the same problem of little-used methods.
Requires authors of subclasses to die() on their own if they don't implement everything. Consistant with Perl's "allow everything so that the programmer can decide how to do things". Something of a tradeoff of laziness in favor of flexibility.
Does what Class::Virtual does, but with compile-time inforcement. This eliminates the problem of subclass authors having to die() on their own. However, its implemented via import(), so if any of your subclasses defines its own import(), the compile-time checking goes away. This puts limits on how subclasses can be implemented, even though a principal point of an abstract class is that we don't care how subclasses are implemented, provided methods x, y, and z exist.
Update: As dws and Elgon point out, I used the definition of "Abstract Class" incorrectly. "Interface" is probably the right term for what I'm looking for. In any case, I suspect the means to implement both of these in Perl would be very similar.
Note: All code is untested, unless otherwise stated