[Grace-core] Statically-known and family-polymorphism

Andrew P. Black andrew.p.black at gmail.com
Thu Nov 20 23:14:29 PST 2014


A while back, we did talk about some sort of “static” declaration — I think that I advocated using the world manifest.   Right now, the motivation for keeping type declarations is that they are more static than defs.

In Grace, we are trying to do two things that are fundamentally at odds.   One is to use the same construct — an object — for everything:  method reuse (aka inheritance), modularity, and dynamic domain modeling.  This parsimony of constructs gives us a small language.  The other is to do lots of static checking, presumably because that will help students find bugs, and because it helps us solve some thorny language design issue, such as whether declarations on the lexical chain or on the inheritance chain have priority.

But it’s hard to do static checking when the base construct of your language is dynamic.   That’s the motivation for restricting inheritance to  “definitively static” objects, which was always something off a kludge.

I felt railroaded into saying “yes” this afternoon to a definition of definitively static that was poorly worded and the consequence of which I didn’t understand.   We should not be making decisions like this.

=======

Now I want to discuss a particular use of objects in Grace to solve the expression problem.   I believe that it should work, but haven’t had time to try it out, and I haven’t thought about whether we can type it.

Rather than using Cook’s “object algebras” — which essential abstract over object construction with another level of methods — I believe that the lack of global variables in Grace should let us add methods to classes more directly.

Suppose that we have a "baseAst” module that defines the classes for the nodes of a syntax tree.    I want to add a pretty(depth) method to all of these nodes.  Can I do it like this?

in module “prettyAst"

	import “baseAst” as base
	
	class request.name(requestName) on(receiver) with(arguments) {
		inherits base.expressionNode(requestName) on(receiver) with(arguments) 

		method pretty(depth) {
			… construct a suitable string …	
		}
	}

	class  methodDef.name(methodName) signature(sig) {
		inherits base.methodDef.name(methodName) signature(sig) 
		
		method pretty(depth) {
			… construct a suitable string …	
		}
	}

	… and so on for every class in "baseAst”.


The client can then 
	
	import “prettyAst” as ast

instead of

	import “baseAst” as ast

and get the benefit of the extra methods.

Are we outlawing this?  I don’t think that we need to, because the meaning of base is statically known, and thus we know statically exactly what methods we get by inheriting base.expressionNode(requestName) on(receiver) with(arguments).

But suppose that there is other stuff in “baseAst” that clients want — some constant declarations, or module-level methods.   Then “prettyAst” has to know about and re-export every one of those definitions.   What we really want to put in “prettyAst" is just the differences between the base and pretty versions — it is a BAD IDEA to have to re-declare everything.   It was for exactly this reason that inheritance was invented!

So we really would like the “prettyAst" module to inherit from the “baseAst" module.   And there doesn’t seem to be an y good reason to prohibit this, because the contents of “baseAst” are statically known.   But I believe that Tim said that his proposal hinged on disallowing inheritance from modules.   The motivation was that 
we wanted to ensure that base.methodDef.name(methodName) signature(sig) has not itself been overridden, or else we couldn’t know what it meant when we inherited from it.   If we allow inheritance from modules, then some object that inherits “prettyAst” could override  base.methodDef.name(methodName) signature(sig), thus changing the meaning of the method methodDef.name(methodName) signature(sig) declared on prettyAst.

I don’t see a clean way out of this that doesn’t throw out th baby with the bathwater.   We already have a kind of attribute in an object that can’t be overridden — a type declaration.   Can classes be overridden?   Can classes override inherited classes, or defs or methods?

It seems to me that our inheritance construct is both too powerful — because it allows arbitrary overriding in ways that cannot be tracked in a modular fashion — and too limited, because it prohibits the simple sharing of pure methods between objects (aka trait composition).  Do we need some more flexible but more static construct for
	- module composition
	- dialect composition
	- class composition
	- type composition

We do need to solve all four of these problems.  I really don’t want to see four separate solutions.   Rather than attacking them piecemeal, I think that we need to look for root causes of  the problems.  If, as I suspect, they have the same root cause, then perhaps they can be solved together.  If that root cause is indeed using an overly-powerful inheritance construct for program (rather than object) composition, then might a more “static” composition construct be the solution?

	Andrew



-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailhost.cecs.pdx.edu/pipermail/grace-core/attachments/20141120/70da03a3/attachment.html>


More information about the Grace-core mailing list