[Grace-core] Inheritance and object initialisation

Andrew P. Black black at cs.pdx.edu
Wed Jul 25 09:25:45 PDT 2012


On 22 Jul 2012, at 4:08, James Noble wrote:

> On 21/07/2012, at 09:27 AM, Kim Bruce wrote:
>> I'm depressed.  
> 
> yep, me too. 

I don't see any reason to be depressed.  I'm surprised that you are surprised that Grace is different from Java.  As far as I recall, it was intended to be different, *especially* around object construction and initialization, which is a mess in Java.

Now, if you can give me an example of something that programmers would typically need to do, and which can't be done gracefully in Grace with object inheritance semantics, *then* I would be depressed.  But all that I have seen so far is that the idioms for constructing objects using inheritance are different in Grace than they are in Java and also different from how they are in Self.   I'm not surprised by that.

> class classCreator.new {
>                                  def x = self
>  print(foo)                                
>     		 method foo{ "hello" }
> }
> 
> 
> class subClass.new {
>   inherits classCreator.new
>   method foo is override { "world" }
> }
> 
> 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)

I'm quite happy for the side-effect of classCreator.new to be the printing of "hello".   As Kim said, putting print statements (or other side-effecting code) in object constructors is something that one probably does only for debugging, and here the debugging code us telling us that we constructed a classCreator object, which is what the code says we do.

Here is Kim's example:

> class C(...) -> T {
>    inherits B.new(...)
>    method m(...)->U is overriding {newmBody}
>    ...
> }
> 
> then I want the constructor for B to run in an environment where self refers to objects from C (i.e., of type T), not those from B. 

By "constructor" I asume that Kim means "Grace object literal", not "the Java special initializer method (called a constructor) that runs after the object has been created by the new primitive".   Well, I think that this desire is unreasonable: inGrace, the object literal in B.new runs before B.new exists, and certainly should do the same thing regardless of the context in which B.new is invoked.   Self in that object literal has to mean the object being constructed. 

Now, if you write an explicit initializer method, as Kim does in his graphics example, (called doSetUp), then that method can be requested on the subobject, or in the super object, depending on the target of the request.   That is, self.doSetUp in the super-object means setUp the super object, and self in the subObject means set up the sub-object.  What could be more natural? 

It's even possible for the sub-object to explicitly request a super.doSetUp if that is what the designer of the framework requires.

I woud have written this code slightly differently: I would probably have provided the window size as arguments to a method openWindow, and then perhaps it would not seem strange for the creator of the application to open it in a window of a specific size.

> 
> Any good examples of inheritance using mutable objects (ideally where the state has changed since it was created)?

We didn't think that this was a common use case, which is why the current spec outlaws it.   One example might be inheriting from a preferences object, where each inheriting object wants to keep the preferences it was given at creation time, even though another object.

The example that I gave at the end of my original message on this topic is a great example of trying to translate a Smalltalk or Java idiom into Grace and finding that it does something different.  Here it is again:

> 
> 	def window = object  {
> 		var border = aBorder.ofColor(self.bordercolor)
> 		...
> 		method borderColor { Color.black }
> 	}
>  
> 
> 	def errorWindow = object  {
> 		inherits window
> 		...
> 		method borderColor is override { Color.red }	
> 	}
> 


My previous solution suggested that window should have a constructor that allows parameterization by color; that would indeed solve the problem, but part of the advantage of inheritance is to *avoid* having to parameterize by everything that might change; instead, we override it.  So, how can we make error windows have red borders without changing the declaration of window?  Like this:

	def errorWindow = object  {
		inherits window
		...
		method borderColor is override { Color.red }	
		border.setColor( borderColor )
	}

This seems quite natural to me.  The request border.setColor might be in practice be in an "open" method that also sets other appearance parameters, such as background color, size, etc.

I think that the common cases of inheritance — where one inherits from an abstract superclass — will work just fine using Grace "delegation-style" inheritance.  This is because the abstract superclass is (in Smalltalk) just a singleton object with no state, which was our use-case when we defined Grace inheritance to clone such an object and then extend it to become the new object.

	Andrew


 


 


More information about the Grace-core mailing list