[Grace-core] Semantics of object/classes

James Noble kjx at ecs.vuw.ac.nz
Thu Aug 9 13:43:01 PDT 2012


replying briefly, as I need to get up properly
 - I don't want to do dynamic binding
 - I think it still may be possible to say something about a "chain" of object constructors
     linked by inheritance making only one object (and that's all we need to say)
 - the writeup of my latest attempt tries to say this

https://projects.cecs.pdx.edu:8443/~black/NewOOL/index.cgi/wiki/BackwardsFactoryInheritance

although it is *still* written in Self-ish terms - not in terms of lexical bindings.

James


On 10/08/2012, at 03:23 AM, Andrew P. Black wrote:

> On 8 Aug 2012, at 23:11, James Noble wrote:
> 
>> On 9/08/2012, at 13:57 PM, Marco Servetto wrote:
>> 
>>>> object { inherits X D... }  //  "inserts" all parts of the object described by D into X
>>> 
>>> For a complete "inherit from objects" semantic, this design require
>>> objects to be dynamically enriched.
>> 
>> if we allow general inheritance from any object, yes.
>> If only from some kind of "factory method" or "class" that 
>> encapsulates and returns an object constructor, then no.
> 
> 
> I think that Marco is exactly right.   I spent a lot of time laying away last night thinking about this, and some things that I have known for a long time came into sharp focus.
> 
> In Smalltalk, classes serve 8 different rôles, one of which is manufacture of its instances, another of which is a template for those instances, and a third being the repository for the instances' methods.
> 
> In Grace, classes serve just the first role.  Objects own their one methods, and don't have templates.  This means that it makes no sense to talk about "inheriting from a factory method".  The factory method doesn't contain the information that you need to inherit — unless you believe that you can extract that information from an analysis of the code in the factory method!

inheriting from the result of a factory method.

> That was why we inherit from objects: objects own their own methods, so it makes sense to ask an object for its methods, and copy them into a new object.

Now I'm confused, cos you wrote: 

>> all of the methods of the superObject, car in the above example, are added to the object being constructed by the object constructor.



>  This is rather like trait-based reuse, except for one vital difference.  In the trait-based languages that I know (which means Smalltalk and Fortress, but not Scala), traits can't have lexical bindings.   In Grace they can.  Hence the careful wording about what happens to lexical binding in my description of Grace inheritance.
> 
> Let me digress for a moment, and point out that I have a _lot_ of difficulty interpreting something that does not mean what it appears to mean.   It's related to  Aspergers Syndrome, I think:  I take wording literally.  This is one reason, perhaps, that I am keen for Grace's syntax to mean what it appears to mean.   As a consequence, I really can't grok 
> 
>>>> object { inherits X D... }  //  "inserts" all parts of the object described by D into X
> 
> If that's what we mean, then we should rite something like
> 
>> X becomes X extended by { D }
> 
> 
> assuming that X is a pre-existing object.
> 
> I don't mind changing the semantics, but if we do, we should change the syntax too.  It will help in our discussions.
> 
> I have a similar difficulty with James's MinimalFactoryInheritance page.  He wrote:
> 
>> The short story is very simple: all of the declarations of the super class, car in the above example, are added to the object being constructed by the object constructor that inherits from that super class
> 
> But the inheritance is not from Car — it's from Car.new.      bicycle could inherit from Car, but that would mean something quite different.   Car.new is not a class, it's an object (that models a car).   Car is a class — an object that models a car factory.  You can choose which one you inherit from, but you have to be consistent.
> 
> Assuming that we do actually mean to inherit from the instance Car.new — and thats where the methods, live, so it seems like a reasonable expectation — what's in that object.  Methods.   Just methods.   Grace objects don't have "slots" or "fields", and never have.   The three declarations, for position, speed and heading, are private to the car object, and the related variables get "dragged along" by the methods that lexically bind to them.  (Since the Claremont meeting, this has been any method in the object; before Claremont, it was just the pair of accessor methods, and if we annotate the var as public, then it's still the accessor method(s).)
> 
> Why does this matter?  It matters because it affects how one designs an object for reuse.  Reuse in Grace is different from reuse in Java (and in Smalltalk) because our objects work differently.   In Grace, if an object  j def's wombat and method frobbit accesses wombat lexically, then the designer of the object DECIDED TO REFUSE TO ALLOW THAT ACCESS TO wombat BE CHANGED by inheriting objects.   It's Grace's version of final.   

in both pages I wrote, I wrote them from a Self-ish perspective, with slots etc.
I don't think this distinction changes things about inheritance - perhaps is does.
I think it's orthogonal.

> If one wants to reuse the object in spite of these efforts by its designer, then the solution is (in an object jk) to override the method frobbit so that it no longer accesses wombat.   If we assume that frobbit was the ONLY method in k that accesses wombat, then wombat will no longer be "dragged along" into object jk that inherits from k.    Alternatively, one can refactor j so that frobbit no longer accesses wombat lexically.  For example, one might make the def of j confidential, which means that accesses from frobbit are now method requests, and are therefor overridable.  sub-objects like jk could then  declare a new constant, say wombat2, and provide a method wombat to access it; now the frobbit method in k is accessing wombat2, though a method request that is dynamically bound, rather than through a lexically bound variable reference.  The important point to note here is that jk does not have to provide any storage for wombat:  it's not used, so it's not "dragged in".
> 
> The reason that I'm so opposed to having sub-objects inherits the initialization code of their super objects is that the super-objects DON'T CONTAIN that initialization code.  They don't contain it any more than after the execution of
> 
> 	def area = length * width
> 	def volume = area * height
> 
> volume contains the arithmetic that computed its value.   If length changes, volume does not.
> 
> This is different from methods.  The code for methods IS in the object.  Methods are more like
> 
> 	def volume = { def area  = length * width ;  area * height }
> 
> Now, if we assign to length and then request volume.apply, the new value of length will indeed be used: that's the meaning of making volume a block.
> 
> Hence, my proposal that we put initialization code in a method, so that the code IS available to inheritors, and can be executed if and when the sub-objects request it.  I don't understand James's claim the the initialization of the super-objects will be performed multiple times, but even if it is, so what?
> 
> Remember that the motivation for object constructors was the ability to create "fully formed" objects.  The consequence of that is that the objects are full-formed when they are created.  There is no initialization code in a Grace object right now, which is why we can't "re-execute" it.  

fine. the catch with that story is per-instance defs.

> The idea that the meaning of the message request
> 
> 	Car.new
> 
> should somehow depend on the bindings that are in existence in the lexical scope SURROUNDING the message request Car.new has been thoroughly explore in languages starting with an implementation mistake in the original LISP.  It's called dynamic scope.   It's generally considered to be a bad idea, but some languages have revived it for special occasion usage — Clojure is one example.  Clojure at least has the wisdom to say explicitly
> 
> (def ^{:dynamic true} x 2)
> 
> if x is to permit dynamic re-binding, and to say explicitly (binding [x 10 ] <code to be executed in the scope of the dynamic binding for x)
> 
> There may be a reason to put dynamic banding in a higher-languge-level of Grace, just so that people teaching the PL class can explain how dynamic binding works without having to switch language.  (The same reason as having matches).  If we do eventually add it, I hope it ill be just as explicit as it is in Clojure.

I don't think we need to do that!

James


More information about the Grace-core mailing list