[plt-scheme] A puzzle for those people doing class.ss stuff

From: Danny Yoo (dyoo at hkn.eecs.berkeley.edu)
Date: Mon Nov 20 19:21:53 EST 2006


On Mon, 20 Nov 2006, Robby Findler wrote:

> Do you realize that you haven't defined any methods in the code below?
>
> It is a subtle point of the class system, but definitions that are 
> otherwise unannotated (ie, don't have a /public or /private etc on them) 
> are private fields.

Yes.  I was just trying to distill the particular issue I was running into 
in some other piece of code.  The module I coded up just pinpoints the 
problem to the call to super-new before the definition of 'x'.

I'm not really writing code like that in real life!  (Unless I'm trying to 
isolate something weird.  *grin*)


The problem is that in the call to super-new in some-class:

     (super-new)

sets 'x' to some certain value.  But subsequently, the define:

     (define x #f)

resets the value.  That's the unexpected behavior.  The fix is to pull 
super-new to after the definition:

     (define (my-mixin super%)
       (class super%
         (override set-x)
         (define x #f)

         (super-new)
         ...))


But this is subtle stuff.  In particular, one reason reason this is odd is 
because this conflicts with the standard Java way of implementing class 
initializers --- in Java, the call to the super's initializer must come 
first.  Whereas in my code, if I do that, it screws things up.


For completeness's sake: in real life, I was defining a mixin for a 
DrScheme unit window that define/override'ed the 
FILE-MENU:BETWEEN-PRINT-AND-CLOSE function, and it looked something like 
this:

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
      (define (diva:menu-option-frame-mixin super%)
        (class super%
          (super-new)
          (define enable/disable-menu-item #f)

          (define/override (file-menu:between-print-and-close)
            (super file-menu:between-print-and-close)
            (set! enable/disable-menu-item
              (new menu-item%
                  [label enable-divascheme-msg]
                  [parent menu]
                  [callback
                   (lambda (menu-item control-event)
                     (send (get-diva-central) switch-toggle))])))

          (define (handle-diva-central-evt evt)
            (match evt
              [(struct diva-switch-on-evt ())
               (when enable/disable-menu-item
                 (send enable/disable-menu-item set-label
                                                disable-divascheme-msg))]

              [(struct diva-switch-off-evt ())
               (when enable/disable-menu-item
                 (send enable/disable-menu-item set-label
                                                enable-divascheme-msg))]
              [else
               (void)]))

          (send (get-diva-central) add-listener handle-diva-central-evt)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

Some of the stuff there is just setting up the observer pattern.  Anyway, 
my handle-DIVA-CENTRAL-EVT told me that my menu item wasn't ever a true 
value, and that was really confusing.  I couldn't figure out why in the 
world ENABLE/DISABLE-MENU-ITEM was getting lost after the call to 
FILE-MENU:BETWEEN-PRINT-AND-CLOSE, because the menu-item was clearly being 
instantiated.

So I cooked up that test-class-scoping code and played with it until I 
could get it to exhibit the same variable-munging behavior.  Anyway, I 
hope that explains things.


Posted on the users mailing list.