[Grace-core] Name resolution in Grace

Andrew P. Black black at cs.pdx.edu
Fri Jul 5 07:41:56 PDT 2013


We have been having a discussion about name resolution in Grace

Method request with explicit receivers (target.method), including operator requests (target + arg), are simple: the named method is requested on the named target.

Method requests with arguments (method(arg)) and an implicit receiver may mean either outer.method(arg) or self.method(arg).  How can we tell?  At one time we said that this was ambiguous and therefore illegal, but I believe that this is untenable.  This is because one may be both in a dialect (which defines an outer object) and inheriting from a super object.  Because one can't change the names of methods in either the dialect or the superobject, such conflicts will sometimes occur, and the programmer can't do anything about them.  I think that the right answer is to request the outer method, if there is one, otherwise to make a self request. If programmers wants the self request, they can write self.method(arg).

The complicated case is a simple identifier like x or foo.   This may be:
	(1) a lexically-bound reference to a variable, definition, or parameter; or
	(2) a dynamically-bound method request to an object that is self, or outer, or outer.outer, etc.

I propose that x should in these cases always be lexically-bound, if a lexical-binding exists.
We can tell if a lexical binding exists; that's the nature of lexical bindings.  To this end, names in an "enclosing" dialect should not be in the lexical scope of entities written in the dialect.  (This was Martin Odersky's suggestion — lexical means within the current compilation unit, and thus visible on the screen in front of me.)

If the programmer intends to make a request, but the name of the method to be requested clashes with a lexically-bound name, then the programmer can get the desired behavior by using an explicit self or outer.

If there is no lexical binding for x, then x should be treated as a request on outer or on self.  Does the lookup for an appropriate method go "out then up" or "up then out"?  We have discussed this before; the problem is that I don't remember the answer, and I'm concerned that nor will our students.   One can make a good argument for either rule, I think.  Up-then-out is consistent with normal overriding, whereas out then up allows dialects to be defined by inheriting from other dialects.  Oops — we just banned inheritance from dialects, so maybe that doesn't matter any more.    

The apparently-simple rule that if there is an ambiguity between up-then-out and out-then-up doesn't work either, because a change to a super-object, or to a dialect, neither of which can I control, can invalidate code of mine that formerly compiled.   Still, such a compilation failure is probably better than having the behaviour of the code silently change!

Now I will try to write down clearly the meaning of x:

— if x is a variable, definition, or parameter in the current lexical scope, then x refers to that variable, definition, or parameter.   ("Current lexical scope" excludes the enclosing dialect, since names defined there are not actually visible "on the screen".)   

— if x is a method defined in the current object, or in any of its super-objects, then x means the method request self.x

— if x is a method defined on the enclosingn object (including inherited methods), then x means outern.x.  Thus, if x is a method defined on the enclosing object (including inherited methods), then x means outer.x; if x is a method defined on the enclosing enclosing object (including inherited methods), then x means outer.outer.x, etc.

— if more than one of the above applies, then x is ambiguous, and the programme is illegal.  The programmer has to fix it, either by adding explicit selfs or outers, or by renaming the variables in the enclosing objects.



 




More information about the Grace-core mailing list