[Grace-core] [Ignore this message] Factory Methods - extra pretentiousness

James Noble kjx at ecs.vuw.ac.nz
Fri Mar 8 22:20:49 PST 2013


This is mostly stuff for reflecting on later... 

> "Where the fool finds something by accident to start with, 
> then maybe twenty years later, by another act of grace, 
> finds it again, having toiled in the forest ever since"  

Jeanette Winterson, quoted in March/April 2013 issue of Believer Magazine,
interviewed by Andrew Tetrick.


looking back to the old emails mid-last year, I noted something like

PICK TWO:
1. self requests ("downcalls") in constructors work normally
2. we can inherit from arbitrary third party objects
3. we have the simple explanation of classes in terms of objects

The reverse mutation scheme broke point 1.  the earlier concatenation
scheme broke point 2. and possibly others.   The raw & cooked merger
scheme broke point 3 (well all of them).   I think this "factory
method" design breaks mostly point 2, and point 3 a little with the
"factory annotation".  It also breaks Andrew's point that "inheritance
should be compositional" as what follow the inherits clause is not
(really) a normal method request, although it comes close enough for
novices, and hopefully the implementation details are just that:
implementation details.


(original wording of the choice)
PICK TWO
1. subClass.new prints "world"
2. we have object inheritance
3. we have the simple explanation of classes in terms of objects (or
vice versa)


In fact, around that time, I also wrote the following...

A Possible Hacky Solution:

The only other option I can think of so far would remove point 2 & 3 -
removing object inheritance, giving us the class behaviour we want,
but also supporting a (mostly) simple description of classes in terms
of generative object literals.   The trick here is perhaps the trick
Kim's been pointing to all along:  saying you can inherit from a
"class-like structure" --- for want of a better term I'll call it a
"classoid".  A classoid is: 
- the result of a class declaration
- a method that returns an object constructor *as a tail-call*
- a definitively static (i.e. **final**) tail-call to a classoid :-)
- (potentially a self-call to a classoid, if we're willing to re-evaluate
	 "virtual superclasses")

This basically avoids all the cloning by using generative object
constructors, and then _requires_ the "inherits" call to statically
resolve to a *dynamically invoked generative object constructor*.
That can go through a bunch of other stuff as long as an object
constructor is eventually reached in the tail position of some method
--- and any method calls are also tail-calls.  At this point, we can
run the object constructor ***in the context of the "whole" object we
are constructing*** -- the whole object here being both of them
super-object and the sub-object, really both of them *concatenated
together.  This can give us the behaviour Kim wants; is build out of
the generative object constructors that Andrew wants; and more-or-less
aligns with the spec and even the Onward! paper :-) In semantic terms,
well yes as Kim suggested, it must be treating object constructors ---
at least those object constructors it is possible to inherit from ---
as classes, rather than objects, thus the insistence of the object
constructor appearing in tail-position of a chain of tail-calls: the
super object constructor is always being run in a lexical context
where its bindings make sense --- there's no attempt to "re-execute" a
constant singleton object.   Rather, we just ensure any object constructor
from when we wish to inherit *can always be "re"-executed* - we 
forbid inheritance from those that cannot be re-executed.

One thing this means is that objects intending to be inherited from
--- even things like "true" --- have to be defined in methods, rather
than as defs holding constant objects. In fact we could weaken the
definition of a "classoid" with another base-case: a *stateless trait*
--- that is an object that purely defines methods, not state.  (Yes,
nesting greatly confuses the issues here: and yes, I'm ignoring that
confusion for now).  If we keep the EGAL rules for objects, then 

method a { object { some stateless trait } }

and

def a = object { some stateless trait } 

pretty much mean the same thing, because if the object is stateless,
every constructor call can returns the same object, or at least the
objects are indistinguishable.  The other advantage of being
stateless, there's no initialisation to worry about.  Of course 
once objects are not stateless, the inheritance rules will
strongly (and apparently arbitrarily) distinguish the two!

Without or without the stateless trait exception, I think this can be
made to work. But it does mean that we're adding a nasty twist into
object constructors, basically making them classes, and turning what
were some implementation-specific restrictions (the definitively
static rules were really there to let implementations use static
object layouts without doing the full tracing JIT thing) into
important semantic rules about which programs make sense,
nasty rules that carve through encapsulation barriers, across
module boundaries, between "compile time" and "link time",
and into the core of the language itself.

James 




More information about the Grace-core mailing list