[Grace-core] Factory Methods - a compromise for inheritance?

James Noble kjx at ecs.vuw.ac.nz
Mon Aug 6 04:54:19 PDT 2012


Factory Methods

Thinking about inheritance, here's one attempt at a compromise.
The main idea here is: objects (or classes) may inherit from 
a request for a _factory method_.  

Factory methods are, basically, methods that are annotated "factory".
A "factory" annotation requires that the annotated method
always returns
 -  a "definitively static" tail-call to another factory method
or
 - an invocation of an object constructor (also in tail position)
or
 - (optionally) the value of an existing "stateless trait" object 


If an inherits clause calls a factory method call chain that
terminates in a call to an object constructor, that object constructor
is executed _with self bound to the "whole" object that will
eventually be returned by the inheriting object constructor.  In other
words initialization works as it does for classes.

e.g. in this example, both object constructors end up constructing the
"same" whole object:

var fooObject

method foo is factory {
  return object {   // object constructor in tail position
     fooObject = self 
  }  
}

def barObject = object {
  inherits foo   // call to a factory method
}

assert (fooObject == barObject) // true

This design permits class "rewriting" into nested objects remains the
same, *but* the class method is annotated as a factory method.

As an option, we could allow inheritance also from "stateless traits"
--- objects without only methods and no inline code.  Stateless traits
never have to be initialized, so they cause no additional problems. 

(We could also permit delegation at high language levels, but that
will get very confusing very fast).

I think this can work for inheritance hierarchies deeper than 1 :-)


In terms of my trichotomy, this maintains:
 - classical inheritance/initialization semantics 
 - object / class "encoding" 
 - so we don't need "richer" classes
but loses
 - real object inheritance (although delegation is still in the back pocket)
 - AND greatly complicates the semantics, we now have these special
 factory methods --- although they are only special *when called from
 inherits clauses* perhaps that makes it even worse. 


The obvious implementation and operational semantics - basically every
factory method has to be compiled *twice*, once for "normal"
invocation and once for "factory" invocation from an inherits clause.
The normal invocation is as normal; the factory invocation has an
extra *implicit* parameter (yes that's bad) encoding the new, fresh
"self" of the  outermost object.  Super-part-object constructors
basically just add their fields, methods, etc into that Self.

An optimized implementation should be able to avoid these costs by
inlining / abstract interpretation the factory methods until all
object constructors are reached, work out its size, and then build the
resulting object in one go. That's what the "definitively static"
clause is for.

thoughts?

James




More information about the Grace-core mailing list