From: Matthew Flatt <mflatt@cs.utah.edu>
To: plt-scheme@po.cs.brown.edu
Subject: [plt-scheme] 299.10
Date: Wed, 23 Jun 2004 16:03:56 -0700

The v299-tagged code in CVS for MzScheme and MrEd is now version 299.10.
(The exp-tagged code is still version 207.1.)

Following tradition for a major version increment of PLT Scheme, we’re
changing the class system --- not as much as in past versions, but
enough to affect most code that uses "class.ss".

The changes are in two parts: a syntactic clean-up for super calls, and
new constructs for augment-only methods. The first part affects most
code; the second affects code that uses certain MrEd methods (which
must now be "augmented" instead of "overridden").

Augment-only methods are the subject of David Goldberg’s OOPSLA’04
paper, "Super and Inner --- Together at Last!" (to appear). I’ll ask
David to post here when the paper becomes available. The short version
is that we’re making Beta-style method augmentation and Java-style
method overriding work together.

Actually there’s one more change to "class.ss": keywords such as
`public’ are now bound to syntactic forms that report out-of-context
uses (much like `unquote’ and `unquote-splicing’). This minor change
can break old code, but I expect that will be rare.

More details are below, and temporary docs are in the usual place:

  http://www.cs.utah.edu/~mflatt/tmp/mzscheme-doc.plt
  http://www.cs.utah.edu/~mflatt/tmp/mzlib-doc.plt
  http://www.cs.utah.edu/~mflatt/tmp/mred-doc.plt

Matthew

----------------------------------------

Super Calls
-----------

A `rename’ clause is no longer necessary in a typical class with
method overrides, due to the new `super’ form. For example,

  (class splotch%
    (rename [super-paint paint])
    (define/override (paint x)
      (super-paint x)
      ....)
    (super-new))

can now be written

  (class splotch%
    (define/override (paint x)
      (super paint x)
      ....)
    (super-new))

An `override’ declaration enables the corresponding (internal) method
name to be used with the `super’ form. The `super’ form is legal only
for expressions within a `class’ (or `class*’, etc.).

For cases where `super’ cannot be used --- either because no overriding
method is declared in a class that calls a super method, or because the
super call is in a lexically nested class --- the `rename-super’ form
can be used just like the old `rename’ form.

The script plt/notes/mzscheme/rename-super-fixup.ss may be useful for
converting code that uses `rename’ to use `super’. (It’s a quick hack.
Let me know if you create a better script.)

Augment-Only Methods
--------------------

A `pubment’ clause declares a method like `public’, but the resulting
method cannot be overridden. Instead, the `pubment’ method can use
`inner’ to dispatch to an augmenting method declared in a subclass. The
word "pubment" is a contraction of "public, but merely augmentable in
subclasses".

The `inner’ expression form includes an expression to evaluate when a
subclass does not provide an augmenting method. A subclass augments a
`pubment’ method with `augment’ instead of `override’. The `augment’
declaration itself is non-overridable, and it can use `inner’ to allow
further augmentation in further subclasses.

Example:

  (define img%
    (class object%
      ;; No subclass can avoid clearing the dc in `paint’,
      ;; but a subclass can augment `paint’ to draw afterward.
      ;; The result indicates the size of the drawn image,
      ;; which is 0 if the paint method is not augmented.
      (define/pubment (paint dc)
        (send dc clear)
        (inner 0 paint dc))
      (super-new)))

  (define box%
    (class img%
      ;; Add a square to the drawing, but allow subclasses
      ;; to draw first. Subclasses cannot skip the final
      ;; square-drawing step. Note that the result of the
      ;; method is the result of the `inner’ call, which is 20
      ;; if the paint method is not augmented.
      (define/augment (paint dc)
        (begin0
         (inner 20 paint dc)
         (send dc draw-rectangle 0 0 20 20)))
      (super-new)))

  (define frbox%
    (class img%
      ;; Add a larger red square as a background.
      (define/augment (paint dc)
        (send dc set-color (make-object color% "red"))
        (send dc draw-rectangle -1 -1 22 22)
        (send dc set-color (make-object color% "black"))
        (inner 22 paint dc))
      (super-new)))

  (send (new img%) paint dc) ; => 0
                             ; and clears the dc

  (send (new box%) paint dc) ; => 20
                             ; and clears the dc,
                             ; then draws a black rectangle

  (send (new frbox%) paint dc) ; => 22
                               ; and clears the dc,
                               ; then draws a big red rectangle
                               ; then draws a black rectangle

An augmentation itself can be made overrideable using `augride’, which
is a contraction of "augment, but allow the augment to be overridden".
Similarly, `overment’ overrides a method, but allows subclasses only
to augment this overridding.

  (define dot%
    (class img%
      ;; This augmentation of img% can be replaced in
      ;;  subclasses.
      (define/augride (paint dc)
        (send dc draw-ellipse 0 0 20 20)
        20)
      (super-new)))

  (define emptydot%
    (class dot%
      ;; Draw nothing, but still claim to have
      ;; drawn something of size 20. The dc is still
      ;; cleared in `paint’ from img%; the override
      ;; replaces only `paint’ in dot%.
      (define/override (paint dc)
        20)
      (super-new)))

  (define frdot%
    (class dot%
      ;; This method re-uses the `paint’ augmentation in
      ;; dot%, and allows further augmentation in subclasses
      ;; (which cannot skip the painting here).
      (define/overment (paint dc)
        (send dc set-color (make-object color% "red"))
        (send dc draw-ellipse -1 -1 22 22)
        (send dc set-color (make-object color% "black"))
        (super paint dc)
        (inner 22 paint dc))
      (super-new)))

Note that `pubment’, `augment’, or `overment’ without an `inner’ call
is effectively the same as `public-final’, `augment-final’, or
`override-final’. However, the `-final’ variants report a class error
if a subclass attempts to augment the method, whereas the non-`-final’
variants allow subclasses to include ans augmentation (that is always
ignored).

In general:

                  Can use `inner’?    Can use `super’?
    public             N                    N
    pubment            Y                    N
    override           N                    Y
    augment            Y                    N
    overment           Y                    Y
    augride            N                    N
    public-final       N                    N
    override-final     N                    Y
    augment-final      N                    N

The `rename-inner’ form is similar to `rename-super’. Like
`rename-super’, it is rarely useful compared to `inner’. A use of a
binding introduced by `rename-inner’ must include a `lambda’ pattern
after the identifier to provide the default expression (i.e., the
expression to evaluate if no subclass augments the method); see the
documentation for further information.

Keywords
--------

The various keywords for class clauses are now all defined as syntax
and exported by `(lib "class.ss")’. Use of a keyword in an expression
positions produces a syntax error.

A complete list of such keywords:

	   private public override augment
	   pubment overment augride
           public-final override-final augment-final
	   field init init-field
	   rename-super rename-inner inherit
	   super inner

MrEd Methods
------------

Some methods in MrEd are not augment-only. They no longer work with
`override’ --- use `augment’, instead.

 top-level-window<%>: can-close?
                      on-close

 editor<%>: on-change
            on-snip-modified
            can-save-file?
            on-save-file
            after-save-file
            can-load-file?
            on-load-file
            after-load-file
            on-edit-sequence
            after-edit-sequence

 text%: can-insert?
        on-insert
        after-insert
        can-delete?
        on-delete
        after-delete
        can-change-style?
        on-change-style
        after-change-style
        after-set-position
        can-set-size-constraint?
        on-set-size-constraint
        after-set-size-constraint

 pasteboard%: can-insert?
              on-insert
              after-insert
              can-delete?
              on-delete
              after-delete
              can-move-to?
              on-move-to
              after-move-to
              can-resize?
              on-resize
              after-resize
              can-reorder?
              on-reorder
              after-reorder
              can-select?
              on-select
              after-select
              can-interactive-move?
              on-interactive-move
              after-interactive-move
              can-interactive-resize?
              on-interactive-resize
              after-interactive-resize