Brent,

On Oct 11, 2005, at 8:17 PM, Brent 'Dax' Royal-Gordon wrote:
Stevan Little <[EMAIL PROTECTED]> wrote:

I would like to propose that class methods do not get inherited along
normal class lines.


I think you're not thinking about many major usage cases for class methods.

Actually I have considered many common usages including those which you describe below, and it is my belief that only a few are truly valid uses and not abuses of class method functionality. What I kept coming back to was that pretty much all the *abuses* of class methods were better done in some other way, and that even the *valid* uses were nothing more than design choices, and could be accomplished in some other manner.

For one example, look at my Cipher suite.  (It's in Pugs's ext/Cipher
directory.)  The Cipher base class implements most of the visible API,
while subclasses simply override a few internal methods; Cipher turns
the wide-ranging, convenient external API into a smaller, more easily
implementable internal API.

Your internal API and your external API have little to do with one another as far as I can tell. The external API is simply a set of convenience functions which create instances of your classes in various ways (very cool ways I might add, especially the functional API, very nice stuff). However, you could easily remove external API, and your internal API would not really suffer, it would only require that the user manually create what your class methods create for you.

While many people think Factories are many times overkill (me among them), what you are doing is a perfect candidate for the Factory pattern. In fact, one could say you are already doing an ad-hoc Factory pattern with your inheritable class methods.

Some of Cipher's methods are class methods, including the
pseudo-procedural .encipher/.decipher and the pseudo-functional
.encipherer/.decipherer methods.  These methods are included
specifically *to* be inherited.

Your documentation says the following things:

The Cipher API's procedural interface is good enough for many purposes. Although the interface is said to be procedural, it is invoked via two class
  methods.

The Cipher API is fundamentally object-oriented; the procedural and functional
  interfaces are layers on top of the object-oriented backend.

Both indicate to me an acknowledgment that you are knowingly abusing the inheritance of class methods to make your functional and procedural APIs work. Now, please don't take this as an insult or slam of some kind. All good programmers know when to abuse language elements to get what they need. However, I am of the opinion that maybe we should leave these old idioms/abuses aside.

In my opinion, class method inheritance is an important part of
class-based OO--almost as important as object method inheritance.

I disagree with you on this point (of course, otherwise I would not have started this thread), but I will admit that inheritable class methods are a very common OO idiom, and that fact (good or bad) should be taken into account.

Removing features simply because their implementation is inconvenient
is not The Perl Way.  If it were, Perl 6 would be Java With Sigils.

To be honest, the implementation is not inconvenient at all, in fact I have already done it twice (correctly at least, the meta-model currently has inheritable class methods, but the implementation is crap).

1) A Mini-MetaModel with Eigenclasses

http://svn.openfoundry.org/pugs/perl5/Perl6-MetaModel/docs/ MiniMetaModel_w_eigenclasses.pl

Whenever I am doing something which has the potential to dig deeply into the core of the meta-model, I do it first with a Mini-MetaModel. (The MMM (mini-meta-model) is a small self-bootstrapping single- inheritance meta-model in under 2-300 LOC and usually which tends to be much easier to "mess with" than the real meta-model.) If you look at the "new" method in Class, you will see it creates an Eigenclass for each class (this is where the class methods get stored), then adding class methods is accomplished with the "add_singleton_method" method. You will find a number of tests towards the bottom of the file which demonstrate the inheritance of the class methods.

2) By using a subclass of Class

http://svn.openfoundry.org/pugs/perl5/Perl6-MetaModel/t/ 37_inherited_class_methods.t

I did this test at autrijus's request, it creates a "ClassWithInheritedClassMethods" class which is a subclass of Class. If you create your classes (Foo, Bar, what have you) using "ClassWithInheritedClassMethods", then you can add class methods, again with the "add_singleton_method", and they are inherited correctly by subclasses.

The code to make "ClassWithInheritedClassMethods" work is only 10 lines long, so as you can see the implementation is not difficult or inconvenient at all.

To properly implement this in the current meta-model prototype would not require all that much more effort than either of these examples.

Now, all this said, I think you make a very important point, which is that such B&D does conflict with "The Perl Way". And that it probably will get in the way of "getting the job done" which is just contrary to what Perl is all about.

Stevan


Reply via email to