Specifically, implementations for the #:defaults keyword in define-generics can
now use define/generic to get at the generic implementation of a method for
which a specific implementation is defined locally. Also, unimplemented methods
are handled properly now in #:defaults. Previously, an unimplemented method in
a #:defaults specification would go into an infinite loop if applied, because
the implementation for the specific type wound up referring to the generic
implementation of the method.
A lot of the back-end implementation of generics changes in this commit:
- The new module racket/private/generic-methods provides a uniform mechanism for
defining method tables and recording static information about generics
groups. Both #:methods in [define-]struct and #:defaults in define-generics
use this framework now. In addition, generics based on existing properties
such as gen:stream, gen:equal+hash, and gen:custom-write now use the struct
from this module to store the names associated with the generics groups.
- Generic methods now expand directly into functions with the appropriate arity,
and refer directly to the appropriate argument to perform generic method
dispatch. The previous implementation used procedure-reduce-keyword-arity to
restrict the arity dynamically, and used list-ref to find the generic
argument.
- Some error messages have changed slightly; hopefully for the better, but this
change did require some changes to tests for specific error messages.