[Grace-core] inheritance and closures

Kim Bruce kim at cs.pomona.edu
Mon Jun 4 15:44:41 PDT 2012


Hi,

Here is a problem I've been puzzling over for quite a while, though I think I finally figured it out.  I believe it is a semantic error in the compiler, but I'm not positive.  Take a look at the program below and then at my explanation in the next few paragraphs.

DrawingCanvas is supposed to be an abstract class in a library that should be specialized for particular uses.  It uses an applet from the processing library.  The methods applet.onSetup, applet.onClick, and applet.start are run as part of the constructor for DrawingCanvas.

Clicker inherits from DrawingCanvas, redefining the method doSomething.  Notice that doSomething is called from DrawingCanvas's onMouseClick(x,y) method.  I had assumed that the overridden doSomething from Clicker would be called when one clicks in the window created by running Clicker.new, but I was wrong.

Running the program creates a 400,400 window when Clicker.new(400,400) is executed.  When the last line of the program (clickingApp.onMouseClick(25,25)) is executed, the program behaves as expected.  That is, the onMouseClick method of DrawingCanvas is executed, which itself calls the overridden doSomething in Clicker.

If the user actually clicks on the window, then the onMouseClick method of DrawingCanvas is executed as before.  However, it now calls the old doSomething from DrawingCanvas rather than the new doSomething from Clicker.

What is happening?  Well, the userMouse.onClick method takes as an argument a block (it looks like a method definition, but it is not -- its signature is onClick(block : Block) -> Void).  Somehow, the self for that block is fixed to be an object of type DrawingCanvas rather than Clicker.  [Note that we never actually created a DrawingCanvas, but its constructor was executed as part of creating the Clicker.]  As a result, when self.onMouseClick is executed in the body of userMouse.onClick (as a result of a mouse click in the window), it executed onMouseClick in DrawingCanvas, and when it called self.doSomething (it doesn't matter whether the self is explicit or not), it called the doSomething associated with DrawingCanvas rather than Clicker.

Is this the correct semantics?  I've been trying to figure that out, given that the closure is what is being passed, and that seems to be statically determined.  However, in the end, I believe it is wrong.  I believe that since this was all being executed as part of the constructor for Clicker, the self should have been the self for Clicker that was bound in the closure.  Thus I should have gotten the semantics I expected -- where the doSomething for Clicker was executed rather than the one for DrawingCanvas.

I'm happy to have someone explain why I'm wrong, but for now I think its a compiler bug.  What do you think?

Kim


import processing
def applet' = processing.applet

class DrawingCanvas.new(width':Number,height':Number){
   def applet = applet'
   def userMouse = applet.mouse
   userMouse.onClick{
       print "clicked mouse in DrawingCanvas"
       self.onMouseClick(userMouse.x,userMouse.y)}
   applet.onSetup {
      applet.size(width',height')
      applet.background(applet.color(255))
      applet.fill(applet.color(255) withAlpha(8))
      print "Executing setup"
   }
   applet.onDraw {
   }
   applet.start

   method onMouseClick(x:Number,y:Number)->Nothing{
      print "user has clicked at ({x},{y}) in DrawingCanvas"
      doSomething
   }

   method doSomething{
      print "doSomething in DrawingCanvas"
   }
}

class Clicker.new(width':Number,height':Number){
   inherits DrawingCanvas.new(width',height')
//   userMouse.onClick{
//       print "clicked mouse in Clicker"
//       onMouseClick(userMouse.x,userMouse.y)}
   method doSomething{
      super.doSomething
      print "doSomething in Clicker"
   }

}

def clickingApp = Clicker.new(400,400)
clickingApp.onMouseClick(20,25)



More information about the Grace-core mailing list