Hi Nathanael,
That was a very cogent description of the Metaclass-Class structure for Classes in Squeak. It _is_ a parallel inheritance hierarchy on both the class side and the metaclass side. This is very hard to discuss, because there are so many design vs implementation details that use the term class.
When you reached my example, however, I believe there is some misunderstanding. I will try to explain. All classes each have a metaclass, which is the class' class. The _implementation_ of the class structure, is that classes are instances of the class, Class. The _implementation_ of the metaclass structure, is that metaclasses are instances of the class, Metaclass. I am trying to use a different Behavior class (not Class) to represent classes. This drives me to consider the implementation for creating new classes.
Before diving into all of that, let me mention that what you are trying to accomplish sounds very interesting. It is like the previous Protocol work, but you are carrying the implementation around as well.
I am also against multiple inheritence. What I am doing is creating an orthogonal vector of method activation. I have redirected the lookup into the image, within a RedirectionContext. The mixin classes have their methods compiled within the scope of the context and get activated by this orthogonal message redirection. I am basically hand building the point at which context, lookup and activate occur, so I want to use an orthogonal Behavior to represent methods to be executed when redirection occurs. Normal message sending to the context use the RedirectionContext class methodDict for behavior.
you said:
In case (1a) you break this parallel inheritance hierarchy because 'MixinClass' is a subclass of 'ClassDescription' but 'MixinClass class' is no subclass of 'ClassDescription class' (in fact,
this is not true, 'MixinClass class' is a subclass of 'ClassDescription class'.
'MixinClass class' == 'MixinClass'). In your concerte example, this means that 'MixinClass' inherits from:
ClassDescription Behavior Object ProtoObject
but 'MixinClass class' (== 'MixinClass') does not inherit from 'ClassDescription class', 'Behavior class', etc.
again this is not true.
Here is my option (1b)
1a) meta _ Metaclass new. meta superclass: MixinClass methodDictionary: MethodDictionary new format: MixinClass format. newClass _ meta new.
I am in the midst of defining a new class, (not defining MixinClass), that I want to represent as an instance of MixinClass, and not as an instance of Class. The porblem lies with the mechanism for creating an instance of Class for this class. It is occurring right here, with meta new. The implementation of this method, looks to the class you are instatiating to get the instSpec and format of the instance. This relies on the superclass chain, of the class. In this case the instance we are creating is a class, therefor we need to know the instSpec of the metaclass. This instSpec depends on the inheritence structure and thus, we inherit the Class instSpec, when we reach the ProtoObject class superclass (I will describe below). I want to substitute the class MixinClass instead of Class. I tried to do this by forcing the superclass of my metaclass to be MixinClass. This works for the instSpec of the class, but, as you point out, it breaks the parallel inheritence of the metaclass.
The inheritance hierarchy, of these two layers, must be parallel, as you point out. I am not sure if parallel is the right term, but idempotent perhaps? For instance:
class level inheritence Object superclass == Object class superclass soleInstance Morph superclass == Morph class superclass soleInstance likewise, in metaclass level inheritence, Object superclass class == Object class superclass Morph superclass class == Morph class superclass
we can verify that these definition objects are instances of the correct class with: Morph class isKindOf: Metaclass Morph isKindOf: Class Object class isKindOf: Metaclass Object isKindOf: Class and even: ProtoObject class isKindOf: Metaclass ProtoObject isKindOf: Class
when we look at the inheritence structure of ProtoObject, this parallel hierarchy, as well as the implementation classes, breaks down. ProtoObject superclass ~~ ProtoObject class superclass soleInstance because the superclass of ProtoObject is nil, while the superclass of ProtoObject class is Class, and doesn't understand soleInstance. ProtoObject superclass class ~~ ProtoObject class superclass because the class of the superclass of ProtoObject is UndefinedObjecct, while the superclass of ProtoObject class is Class. Furthermore, (ProtoObject superclass class isKindOf: Metaclass) not (ProtoObject superclass isKindOf: Class) not
Typically the class side inheritance are instances of Class and the metaclass side inheritence are instances of Metaclass. This is changed at ProtoObject class. It's superclass is the class, Class. (we are in the metaclass inheritance layer).
Ok, I'll stop here until I can determine a good way to graph this using ascii. Here's a try: (paranthesis is the class of the metaobject)
class inheritence nil (UndefinedObject) -> ProtoObject (Class) -> Object (Class) -> Morph (Class)
metaclass inheritence Class (Class) -> ProtoObject class (Metaclass) -> Object class (Metaclass) -> Morph class (Metaclass)
I want the following class inheritence nil (UndefinedObject) -> ProtoObject (Class) -> Object (Class) -> MyMixin (MixinClass)
metaclass inheritence Class (Class) -> ProtoObject class (Metaclass) -> Object class (Metaclass) -> MyMixin class (Metaclass)
but I think I have to have: class inheritence nil (UndefinedObject) -> MixinProtoObject (MixinClass) -> MixinObject (MixinClass) -> MyMixin (MixinClass)
metaclass inheritence MixinClass (Class) -> MixinProtoObject class (Metaclass) -> MixinObject class (Metaclass) -> MyMixin class (Metaclass)
I hope this helps the discussion!!!!!!! ;-)
cheers, Rob
-----Original Message----- From: Nathanael Schärli [mailto:n.schaerli@gmx.net] Sent: Monday, January 28, 2002 9:52 AM To: squeak-dev@lists.squeakfoundation.org Subject: Re: [Q] mixin pattern - how to use an alternate Behavior for Class
Hi Rob,
<snip>
Now, to my work on mixins. Whenever I was designing and implementing an application in Squeak (or Smalltalks), I have felt very limited by the fact that there is only single inheritance. As soon as there are classes with responsibilities that fulfill more than just one single aspect, this urges the programmer to duplicate code. On the other hand, I have never been happy with the rather complex multiple inheritance algorithms where the programmer easily looses track of what actually happens and which method is finally invoked (such as in C++). Java's interfaces are actually very nice (simple), but they also don't solve to code duplication problem. So, why not using a simple concept that is similar to interfaces, but actually allows implementations (but no state)?
--> Idea of stateless mixins with the features such as:
- Mixins are first class entities (obvious in Squeak)
- Mixins have reflective aspects such as 'provided' and
'required' methods.
- The required methods are basically the glue that is
necessary to use a mixin in another class or another mixin.
- If a class implements several mixins, they are not ordered.
This means that the programmer has to resolve all the conflicts manually.
- An extension of the browser allows to see which mixins are
implemented by a class, how the glue methods are defined and how the conflicting methods are defined.
- Mixins can be automatically derived from existing classes.
Thereby, access to instance variable and the class is automatically replaced by methods that have to be defined when the mixin is used (required methods). A class and the derived mixin are (per default) related. This means that when a method of a class gets changed, the corresponding mixin gets also adjusted.
I am just about to implement a first version of these "Stateless Mixins" with features as mentioned above (and some more). The main goal is to be able to group a "(partially) independent set of related methods" as a first class entity and to reause them in a very simple way (therefore no state). I think that one of the keys for that is a good UI that allows the programmer to see what is actually going on.
Cheers, Nathanael
Hi Stef,
Actually, mine is much more special case than MixinClass.
It is called
RedirectorMixin. I intercept method lookup, in the vm, and
redirect into
the image so I can manipulate this lookup. I am writing
the Mixin in
order to have class-based methods to dispatch through. The
reason for creating
a special class was to allow this class to be manipulated in
the browsing
tools.
I'm quite sure there are other aspects of mixin that I am
not addressing
in my special case. ;) I look forward to hearing about
them and from
Nathanael.
Cheers, Rob
At 02:06 AM 1/28/2002, you wrote:
Hi Rob
we are working on mixin (not like yours in fact) mixin are
not only about
compiling in a different scope ;)
I think that we have kind of similar questions ;) Nathanael will certainly get ion contact with you.
Stef
I am trying to create a mixin class which compiles it's
methods 'in'
the
scope of a different class. One way to go would be to
have class side
#compile methods which switches the class used to
compile the method
in. I
would need a classVariable to hold this contextClass
and off we go.
An alternative mechanism that I am exploring, is to
have a different
subclass of ClassDescription (or Class), which has an
instance method
contextClass, and the compile methods are overridden on
the instance
side
of this MixinClass.
So I have a MixinClass, which has roughly identical
protocol to Class
and I
am now adding a set of methods to ClassBuilder to
create this class
(instance of MixinClass). The problem is that I am not
sure what to
set
the superclass of the Metaclass instance too. (1b) If
I leave it
alone, my
class is an instance of Class. (1a) If I force it to
MixinClass, then
my
class is an instance of MixinClass and my instance
methods are ok, but
the
class-side confuses me a little - I have broken the metaclass
superclass
inheritence. Do I really need to have a
MixinProtoObject to root
everything with MixinClass class as the first metaclass
superclass, or
can
I stitch myself into a different point in the hierarchy
and still have
my
class be an instance of MixinClass, rather than Class,
but maintain
the
correct metaclass inheritence? I believe it all relies on the implementation of 'meta new', especially with
Interpreter>>formatOfClass:
aClass, where aClass is a metaclass instance.
Cheers, Rob
1a) meta _ Metaclass new. meta superclass: MixinClass methodDictionary: MethodDictionary new format: MixinClass format. newClass _ meta new.
1b) meta _ Metaclass new. meta superclass: newSuper class methodDictionary: MethodDictionary new format: MixinClass format. newClass _ meta new.
- newClass
superclass: newSuper methodDictionary: MethodDictionary new format: newFormat; contextClass: aContextClass; setInstVarNames: instVars; organization: nil. ^newClass
-- //////////////////////////////\ Nathanael Schärli Rüttenenstrasse 41 CH-4515 Oberdorf, Switzerland Phone: +41 32 622 89 03 Fax: +41 32 621 78 50 Email: n.schaerli@gmx.net //////////////////////////////\
you said:
In case (1a) you break this parallel inheritance hierarchy because 'MixinClass' is a subclass of 'ClassDescription' but 'MixinClass class' is no subclass of 'ClassDescription class' (in fact,
this is not true, 'MixinClass class' is a subclass of 'ClassDescription class'.
'MixinClass class' == 'MixinClass'). In your concerte example, this means that 'MixinClass' inherits from:
ClassDescription Behavior Object ProtoObject
but 'MixinClass class' (== 'MixinClass') does not inherit from 'ClassDescription class', 'Behavior class', etc.
again this is not true.
Here is my option (1b)
1a) meta _ Metaclass new. meta superclass: MixinClass methodDictionary: MethodDictionary new format: MixinClass format. newClass _ meta new.
- newClass
superclass: newSuper methodDictionary: MethodDictionary new format: newFormat; contextClass: aContextClass; setInstVarNames: instVars; organization: nil. ^newClass
Rob,
Yes, you are right! I didn't read the example right! You define here a new class (not MixinClass) which has MixinClass as the superclass of the metaclass. Therefore, the parallel inheritance chains break for this new class and not for MixinClass.
Nathanael
At 02:12 AM 1/29/2002, you wrote:
you said:
In case (1a) you break this parallel inheritance hierarchy because 'MixinClass' is a subclass of 'ClassDescription' but 'MixinClass class' is no subclass of 'ClassDescription class' (in fact,
this is not true, 'MixinClass class' is a subclass of 'ClassDescription class'.
'MixinClass class' == 'MixinClass'). In your concerte example, this means that 'MixinClass' inherits from:
ClassDescription Behavior Object ProtoObject
but 'MixinClass class' (== 'MixinClass') does not inherit from 'ClassDescription class', 'Behavior class', etc.
again this is not true.
Here is my option (1b)
1a) meta _ Metaclass new. meta superclass: MixinClass methodDictionary: MethodDictionary new format: MixinClass format. newClass _ meta new.
- newClass
superclass: newSuper methodDictionary: MethodDictionary new format: newFormat; contextClass: aContextClass; setInstVarNames: instVars; organization: nil. ^newClass
Rob,
Yes, you are right! I didn't read the example right! You define here a new class (not MixinClass) which has MixinClass as the superclass of the metaclass. Therefore, the parallel inheritance chains break for this new class and not for MixinClass.
Hi Nathanael,
We are on the same page now, I believe, you with my problem and me with a clearer understanding of the way this is structured. Superb! The reason my original attempt of:
1b) meta _ Metaclass new. meta superclass: newSuper class methodDictionary: MethodDictionary new format: MixinClass format. newClass _ meta new.
doesn't work is not due to the shape of the instance. It really is shaped to be a MixinClass, due to the format of the metaclass. The problem is that the metaclass inheritance doesn't include MixinClass, so none of the protocol is understood. The only way I was able to make this work is to break the inheritance of the metaclasses. Wow! Unless we break the multiple inheritance rule, there doesn't seem to be a way to maintain the inheritance structure, at the metaclass level, and have my new class (MyProxyMixin) understand MixinClass protocol. Would you agree?
you also wrote:
Yes, that's right, there are no -direct- instances of Class. All the ST-80 "classes" (Object, Integer, etc.) are instances of their metaclasses (Object class, Integer class, etc.) and these are again instances of Metaclass. However, since Object class, Integer class etc. are subclasses of Class (try 'Object class superclass superclass'), the ST-80 "classes" Object, Integer, etc. are subinstances of Class. (Try 'Class allSubInstances').
Summary:
- The ST-80 "metaclasses" Object class, Integer class, etc. are subclasses
of Class and instances of Metaclass 2) The ST-80 "classes" Object, Integer, etc. are -instances- of subclasses of Class (namely, of the metaclasses mentioned in 1).
You know, I have probably read something that said that very thing and just didn't read or think carefully enough about it's implications. Now that I am on this side of the fence, I see the structure clearly. All of the metaclasses must inherit from Class, or none of it works. The only way to change the Behavior representing a class is to root a new hierarchy with the new Behavior as the superclass of the first metaclass. This may not be a bad idea, since I don't plan on having instances of the resulting class.
Like this:
class inheritence nil (an UndefinedObject) -> MixinProtoObject (shape of MixinClass) -> MixinObject (shape of MixinClass) -> MyMixin (shape of MixinClass)
metaclass inheritence MixinClass (Class) -> MixinProtoObject class (a Metaclass) -> MixinObject class (a Metaclass) -> MyMixin class (a Metaclass)
Cheers, Rob
Hey Rob,
We are on the same page now, I believe, you with my problem and me with a clearer understanding of the way this is structured. Superb! The reason my original attempt of:
1b) meta _ Metaclass new. meta superclass: newSuper class methodDictionary: MethodDictionary new format: MixinClass format. newClass _ meta new.
doesn't work is not due to the shape of the instance. It really is shaped to be a MixinClass, due to the format of the metaclass. The problem is that the metaclass inheritance doesn't include MixinClass, so none of the protocol is understood. The only way I was able to make this work is to break the inheritance of the metaclasses. Wow! Unless we break the multiple inheritance rule, there doesn't seem to be a way to maintain the inheritance structure, at the metaclass level, and have my new class (MyProxyMixin) understand MixinClass protocol. Would you agree?
Yes, I agree and I really enjoyed talking with you about these "meta-things". It's amazing, but whenever I get back into the "ST-80 meta-world", it takes me some mind-work until I completely understand it again. (And I have already thought about it many times). This fact gives me the feeling that the class and meta-level organization of ST-80 is not as easy as it should be. I hope I'll find the time to work on it at some point...
Cheers, Nathanael
At 03:34 AM 1/30/2002, you wrote:
Hey Rob,
Yes, I agree and I really enjoyed talking with you about these "meta-things". It's amazing, but whenever I get back into the "ST-80 meta-world", it takes me some mind-work until I completely understand it again. (And I have already thought about it many times). This fact gives me the feeling that the class and meta-level organization of ST-80 is not as easy as it should be. I hope I'll find the time to work on it at some point...
Hi Nathanael,
Thank you for showing me the way to clarity. I also enjoyed it. I alsways kinda knew about the metaclass-class structure and the inheritance structure, but I wasn't feeling it. I am now.
What is your feeling for the ease of manipulating a shared prototype environment like Self. I don't have any experience with it. In trying to get my Mixin class to show up in the Browser, along with knowing that delegation would solve this mixin problem as well, I keep wondering how a delegative model would be browsed and searched and displayed. I also wonder how we could mix the two models, yet have a consistent browsing experience. Does Self even have a 'class' browser?
Cheers, Rob
What is your feeling for the ease of manipulating a shared prototype environment like Self. I don't have any experience with it. In trying to get my Mixin class to show up in the Browser, along with knowing
that
delegation would solve this mixin problem as well, I keep wondering how a delegative model would be browsed and searched and displayed. I also wonder how we could mix the two models, yet have a consistent browsing experience. Does Self even have a 'class' browser?
Hi Rob,
Your thoughts are very interesting, especially what you said about delegation. When I wrote a little bit about my work on mixins, I didn't mention delegation, but in fact, I am working on a flexible but -simple- model that supports both mixins and delegation in a consistent way. Simplicity is really the my main goal and I believe that one of the reasons that multiple inheritance and mixins are not very well supported by current languages is the fact that it can make the code too complicated, and as a consequence, a programmer has a hard time to understand what is actually going on.
I really think that a good UI (a good browser) is one of the key issues to achieve a clear and simple mixin (and delegation) model. The UI of a programming language (in ST, the browser) is the way a programmer looks at (and edits) the code. Thus, it is the responsibility of the browser to do that in a way that supports the programmer in writing and understanding a program. If the semantic model of a programming language gets richer (e.g. if there is a model for mixins/delegation), it is important that also the UI gets richer and supports the programmer in using and understanding these new features.
The last days, I have been working on a browser extension for supporting my model of mixins/delegation and although it is not running yet, it looks pretty promising. Nevertheless, I think that this is only one step into the right direction. In the long-term the UI of such a programming language should allow the user to switch freely between different views of the same program. This means that a program should be represented in a way that allows generating these different views and also allows the prorammer to inspect and manipulate the characteristics of the program that are represented in these individual views.
Cheers, Nathanael
squeak-dev@lists.squeakfoundation.org