[Grace-core] Dialect Design Proposal

Andrew P. Black black at cs.pdx.edu
Mon Dec 10 09:30:36 PST 2012


I thought that I had sent this last week, while preparing for WG2.16, but just found it unsent on my office computer.  

Here is the code that's equivalent to Kim's Java code, in Smalltalk.  It prints Bottom:

Object subclass: #Top
	instanceVariableNames: ''
	category: 'InheritanceExamples'

Top methodsFor: 'printing' 
x
	Transcript show: 'Top'; cr; flush 


Top methodsFor: 'initialize-release' 
initialize
	self x.
	^ self 

Top subclass: #Bottom
	instanceVariableNames: ''
	category: 'InheritanceExamples'

Bottom methodsFor: 'printing' 
x
	Transcript show: 'Bottom'; cr; flush

And here is the equivalent code in Grace.  It also prints Bottom.

def Top = object {
    method construct is public {
        object {
            method initialize is public {
                self.x
                self
            }
            method x {print "Top"}
        }
    }
    method new is public {
        self.construct.initialize
    }
}

def TopCopy = object {
    method construct is public {
        object {
            method initialize is public {
                self.x
                self
            }
            method x {print "top"}
        }
    }
    method new is public {
        self.construct.initialize
    }
}


def Bottom = object {
    inherits TopCopy
    method construct is override {
        object {
            inherits Top.construct
            method x is override {print "Bottom"}
        }
    }
}
    
Bottom.new

What's the point?  I could, of course, write code in both languages to print Top, or both Top and Bottom.
I can do this in Smalltalk because there is a clean separation between object construction (accomplished by Behaviour>>BasicNew) and object initialization (accomplished by an initialize method in the object).  
My Grace program has this same separation, so I can get the same effect.

The problem is that the Grace program is, in my view, unnecessarily verbose.  Look at the object Top.  It is pure code, that is, it captures no state.  So you might think that top and TopCopy would be equivalent (their bodies are indeed identical).

Unfortunately, this is not so.  If Bottom were to inherit from Top, rather than TopCopy, 

def Bottom = object {
    inherits Top
    ...

the program would get into an infinite recursion and blow the stack.   Can you see why?  Don't scroll down to look until you can ;-)




















It's because of the mutation semantics of inheritance.  The definition of Bottom would mutate Top to have an overriding construct method, which itself requests Top.construct.  Because of this, both these versions of the program are strictly illegal in Grace today.  We force programmers to add one more level of indirection:

def M = object {
    method top is public {
        object {
            method construct is public {
                object {
                    method initialize is public {
                        self.x
                        self
                    }
                    method x {print "top"}
                }
            }
            method new is public {
                self.construct.initialize
            }
        }
    }
}

def Bottom = object {
    inherits M.top
    method construct is override {
        object {
            inherits M.top.construct
            method x is override {print "Bottom"}
        }
    }
}
    
var b := Bottom
b.new

(The var b := Bottom; b.new at the end; this is there to get around a bug in the type checker, which I don't know how to turn off, and won't let me write Bottom.new)

In this version, instead of using the def Top, we use a method top in the object M (for "maker").  The top method makes (a fresh copy of) the same, immutable object that used to be Top.   To see how pernicious the current semantics are, if I replace 

method  top is public {
        object {

by

def top is public, readable = 
        object {

which (I claim) most readers would think is equivalent, we are back to the infinite recursion and the blown stack.

As a matter of sound software engineering, I would second (or is it third?) the proposal that object construction should not involve requests on self, or the use of self as an argument.  It's fine to put such things in object initialization, since initialization takes place after the object is fully constructed.

If initialization after construction is required frequently enough, we could change the meaning of the class syntax to do it.  I haven't needed it yet, but I have frequently needed to re-use methods from immutable objects.

	Andrew



-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mailhost.cecs.pdx.edu/mailman/private/grace-core/attachments/20121210/ca8960cb/attachment.html>


More information about the Grace-core mailing list