RFC 254 (v1) Class Collections: Provide the ability to overload classes
[email protected] (Perl6 RFC Librarian) 18 Sep 2000 05:49:28 -0000
| Newsgroups | perl.perl6.language.objects,perl.perl6.announce.rfc |
|---|---|
| Message-ID | <[email protected]> |
This and other RFCs are available on the web at http://dev.perl.org/rfc/ =head1 TITLE Class Collections: Provide the ability to overload classes =head1 VERSION Maintainer: Greg Williams <[email protected]> Date: 17 Sep 2000 Mailing List: [email protected] Number: 254 Version: 1 Status: Developing =head1 ABSTRACT Currently, class methods can be overloaded through sub-classing. This functionality is perhaps the most compelling aspect object oriented programming offers. This mechanism allows one to extend the functionality of pre-existing code without significant copying or rewriting. However, there exists situations in which it is desirable not to extend methods, but entire classes. It is proposed that classes be able to be grouped into collections. Collections would have the ability to inherit from other collections just as classes inherit from other classes. A sub-collection would overload super-collection classes exactly like subclasses overload superclass methods. =head1 DESCRIPTION In a typical HASA relationship, the method call to construct the encapsulated object must make the call against either a class name, or a scalar containing the class name. In either case the name of the class must be known and hard coded in some part of the code. Consider two classes, Forest and Frog (both of which you found on CPAN). A Forest object HASA Frog object. The Frog object has a method C<speak> which prints the noise a frog makes. The Forest object has a method C<make_noise> which prints a noise you might hear in the forest (like a frog!): package Forest; sub new { my $class = shift; my $frog = Frog->new; return bless( { frog => $frog }, $class ); } sub make_noise { my $self = shift; $self->{frog}->speak; # prints "ribbit ribbit"; } package Frog; sub new { my $class = shift; return bless( {}, $class ); } sub speak () { print "ribbit ribbit"; } sub jump (); sub croak (); # ;-) In English this is fine, but now let's say you need the Forest class to work in Japanese as well (Japanese frogs 'kerokero', they don't 'ribbit'). The Frog class is maintained by another developer however, and you'd rather not make changes to it directly. You can subclass Frog and provide your own C<speak> method like so: package Frog::Japanese; @ISA = qw( Frog ); sub speak { print "kerokero"; } Here's where the problem lies. Even though we now have a subclass of Frog, the Forest class is still referencing the original Frog class and not Frog::Japanese. In order for Forest to reference Frog::Japanese, you could edit the Forest class and change all occurances of Frog to Frog::Japanese, but that is probably not wise. Firstly, although you may be using a relativly small subset of the features of Forest, the code may contain many references to the Frog class, each of which you must now change. Secondly, and most importantly, by maintaining a locally modified version of Forest you make it difficult to upgrade Forest from CPAN in the future (this rationale just stopped you from making changes to the Frog class, after all). Assuming you did change your copy of Forest, you'd end up with a C<new> constructor similar to this: package Forest; sub new { my $class = shift; my $frog = Frog::Japanese->new; return bless( { frog => $frog }, $class ); } Now the Forest is specifically Japanese though, and can't be used in English anymore! In perl 5, a logical solution is to subclass Forest for a specific locale, with each subclass specifying which language (class) to use: package Forest::Japanese; @ISA = qw( Forest ); sub frog_class { 'Frog::Japanese' }; package Forest::English; @ISA = qw( Forest ); sub frog_class { 'Frog' }; package Forest; sub new { my $class = shift; my $frog = $class->frog_class->new; return bless( { frog => $frog }, $class ); } At this point, we must stop and question whether all this work should be necessary just to change one return value of one method. A better solution (albeit not currently possible) would be to 'overload' the Frog class with a new Japanese version (also named 'Frog'). The Japanese version of the Frog class would inherit (in a slightly altered sense) everything but the C<speak> method from the CPAN version of Frog, and all static calls to Frog methods would actually be made against the new Japanese version. Another example of where this feature would be helpful is when a large number of classes inherit from a single superclass and it is desirable to extend said superclass without making modifications to any subclasses. This has tremendously powerful implications in the area of data inheritance as this would allow the addition of fields to a superclass through L<fields> (or the feature of similar functionality in perl6) thus affecting all subclasses of that superclass. Therefore, it is proposed that a method of defining collections of classes be implemented. A collection would encompass a set of classes that inherited from and referenced one another (most likely a full application or library). By creating a new collection with only the classes you wish to change (such as a superclass) and having this new collection inherit from the base collection, classes will become able to overload other classes. I am unsure of what syntax this feature would employ, both in declaring membership of a collection, and in declaring inheritance from a collection. I can envision a pragma that might suffice: package Frog; use collection member => 'Japanese'; #declares collection membership use collection isa => 'BaseImplentation'; #declares collection inheritance but am interested to hear suggestions for other ways this might be accomplished. I am unaware of any OO language that allows overloadable classes as described here, and have seen them described only once, but have run into many situations in which they would make sense. I would like to discuss the possibility of this feature for perl 6, and hear what others perceive as the implications of this sort of feature on the perl object model (both good and bad). =head1 IMPLEMENTATION I'm not big on internals, but: =over 4 =item * Class Names Would No Longer Be Unique A given class name would not be guaranteed to be unique. A namespace/collection pair would specify a unique package (for lack of a better term). =item * Method Lookup Method lookups would need to examine the collection inheritance tree to determine which class (that is, in which collection) to dispatch method calls to. =back =head1 REFERENCES Tim Sweeney, "A Critical Look at Programming Languages" http://www.gamespy.com/legacy/articles/devweek_b.shtm