On Mon, Jul 11, 2005 at 09:46:30AM -0400, Stevan Little wrote: : Ingo, : : On Jul 11, 2005, at 9:16 AM, Ingo Blechschmidt wrote: : >Hi, : > : > class Foo {} : > class Bar is Foo {} : > : > Bar.new.isa(Object); # true : > Bar.new.isa(Class); # false : > Bar.new.isa(Foo); # true : > Bar.new.isa(Bar); # true : > # These are clear, I think. : : Yes, these all make sense to me. : : > : > Bar.isa(Object); # true : > Bar.isa(Class); # true : > Bar.isa(Foo); # ? (my guess: false) : > Bar.isa(Bar); # ? (my guess: false) : : I am not sure about this. I think that .isa as a class method should : behave much as it does for an instance method.
Right, or you can't easily decide whether Bar isa Foo in the abstract. You need to able to reason about the relationships of user-defined classes in the absence of instances. : If we start supporting : things like Bar.isa(Class) then we start exposing the soft underbelly : of the meta-model to the outside world. Which IMO might not be a good : idea. Bar.isa(Class) probably false in any event, since I think Class is probably a role rather than a class. But "Class" is almost certainly not the name of the metaclass either. Or at least, it's not the name of *both* metaclasses (counting the Class role as one of them). Basically every user-defined class has a Platonic description (known as its "Class") and an Aristotelian description (known as its "MetaClass"). If "Class" is a valid name for a class, it's the Platonic one, not the Aristotelian one, and it would be a class only because "Class" can refer either to the role or to an anonymous class generated from the role, if we follow the idea that Int is both a role and a class. So maybe Bar.isa(Class) in that sense. Or maybe we should force .isa false even if there is an associated anonymomus class, just to keep things straight. So what is certainly true is that Bar.does(Class), where the Class role describes the Platonic interface of items like Bar. That is to say, Bar is the stand-in for all the members of its class when you don't actually have a member. Its Platonic role is to know about Barness, not about classness. We call call it the dispatcher class because it knows how to dispatch things of type Bar whether you actually have an instance of type Bar or not. That's why method calls on it can do things like call constructors. But it doesn't know much about any of the grubby Aristotelian workings of the metaclass. It just knows there is one, and that it can delegate all the messy practicalities to it. I suspect the metaclass of "Class" actually has the name "class" or "CLASS", and the metaclass of a Role is actually "role" or "ROLE". Perhaps the "class" and "role" keywords are just specific examples of the grammar being smart enough to treat declared metaclasses as BEGIN analogues. But maybe it's smarter to keep the "class" and "CLASS" identifiers at arms length from each other. (If for no other reason, to keep our sanity while discussing them.) So anyway, that gives us something like: Bar.isa(Foo); # true Bar.isa(Bar); # true Bar.isa(Class) # false presuming Class is only a role Bar.does(Class) # true Bar.does(CLASS) # false Bar.meta.isa(Foo); # false Bar.meta.isa(Bar); # false Bar.meta.does(Class) # false Bar.meta.isa(CLASS) # false presuming CLASS is only a role Bar.meta.does(CLASS) # true You know, this class/role distinction might just be what saves our collective bacon on the usual infinite regress of metaclasses, if a metaclass turns out to be an object of anonymous class but named role. The bootstrap might reside entirely in the code that constructs the metaclass instance of anonymous class but filling the CLASS role in its abstract interface. I mentioned the idea of autogenerating a class Int from a role Int, but maybe some roles don't allow themselves to be autogenerated into classes, and maybe CLASS is one of them. And it sounds to me like the absence of that feature is caused simply by ROLE's autogenerate interface being left with an implementation of {...} and not overridden in the anonymous metaclass representing the CLASS role. So I guess the deep answer to the infinite recursion problem is that, yes, it's metaclasses all the way down, but if you actually try to pursue it, you'll at some point run into "method not yet implemented" because nobody has cared about it that deeply yet. So we basically get the possibility of mapping to anyone's metamodel without actually having to commit to the fanciest one. I think I like that, even if I don't understand it. Or maybe *because* I don't understand it. Larry