Next: , Previous: , Up: methods   [Contents][Index]


7.2 Virtual methods

The clause virtual-method allows the definition of virtual methods associated to a record–type. Virtual methods work almost like concrete methods, but the rules of overriding are different: with virtual methods we request run–time dynamic dispatching, to have the methods of the sub–types take precedence over the methods of the super–types.

NOTE Virtual methods must have an implementation, there are no abstract methods.

Example:

(define-record-type <super>
  (virtual-method (doit)
    1))

(define-record-type <sub>
  (parent <super>)
  (method (doit)
    2))

(define (super-fun {O <super>})
  (.doit O))

(define (sub-fun   {O <sub>})
  (.doit O))

(define O
  (new <sub>))

(super-fun O)   ⇒ 2
(sub-fun   O)   ⇒ 2

we see that even though the function super-fun accesses the instance of <sub> with the type specification <super>, the actually called method is the one defined by <sub>.

The overriding method’s type signature must be a sub–type of the overridden method’s type signature. For example, the following definitions are fine:

(define-record-type <super>
  (fields value)
  (virtual-method ({doit <number>} {S <nestring>})
    (.value this)))

(define-record-type <sub>
  (parent <super>)
  (virtual-method ({doit <fixnum>} {S <string>})
    (.value this)))

because:

(type-annotation-super-and-sub?
   (lambda (<nestring>) => (<number>))
   (lambda (<string>)   => (<fixnum>)))
⇒ #t

while the following definitions will cause a syntax violation exception at expand–time:

(define-record-type <super>
  (fields value)
  (virtual-method ({doit <number>} {S <nestring>})
    (.value this)))

(define-record-type <sub>
  (parent <super>)
  (virtual-method ({doit <fixnum>} {S <vector>})
    (.value this)))

because:

(type-annotation-super-and-sub?
   (lambda (<nestring>) => (<number>))
   (lambda (<string>)   => (<vector>)))
⇒ #f

Once a method has been defined as virtual in a super–type, it does not matter if the sub–type makes use of method, virtual-method or seal-method: all these clauses will override the super–type’s method if they use the same name. Example:

(define-record-type <super>
  (virtual-method (darkness)
    1)
  (virtual-method (light)
    2))

(define-record-type <sub>
  (parent <super>)
  (method (darkness)
    11)
  (virtual-method (light)
    22))

(define {P <super>}
  (new <sub>))

(.darkness P)   ⇒ 11
(.light    P)   ⇒ 22

Notice that it is not possible to define a sub–type having a field with the same name of a super–type’s virtual method; the following definitions will cause an expand–time exception:

(define-record-type <super>
  (method (doit)
    1))

(define-record-type <sub>
  (parent <super>)
  (fields doit))
error→ &syntax

The clause seal-method seals a method name so that the sub–types can no more use it; it does not matter if the super–types actually use it or not.


Next: , Previous: , Up: methods   [Contents][Index]