On this page:
define/ generic

4.4 Generic Interfaces

 (require racket/generic)

A generic interface allows per-type methods to be associated with generic functions. Generic functions are defined using a define-generics form. Method implementations for a structure type are defined using the #:methods keyword (see Defining Structure Types: struct).


(define-generics id [#:defined-table defined-table-id]
  [method-id . kw-formals*]
kw-formals* = (arg* ...)
  | (arg* ...+ . rest-id)
  | rest-id
arg* = arg-id
  | [arg-id]
  | keyword arg-id
  | keyword [arg-id]
maybe-defaults = 
#:defaults ([pred?
             method-impl ...]

Each method-id’s kw-formals* must include a required by-position argument that is free-identifier=? to id. That argument is used in the generic definition to locate the specialization.

When defined-table-id is provided, it is defined as a procedure that takes an instance of the generics and returns an immutable hash table that maps symbols corresponding to method names to booleans representing whether or not that method is implemented by the instance. This table is intended for use by higher-level APIs to adapt their behavior depending on method availability.

When maybe-defaults is provided, each generic function uses pred?s to dispatch to the given default implementations, method-impls, before dispatching to the generic method table. The syntax of the method-impls is the same as the methods provided for the #:methods keyword for struct.

The id/c combinator is intended to be used to contract the range of a constructor procedure for a struct type that implements the generic interface.


(define/generic local-id method-id)

  local-id : identifier?
  method-id : identifier?
When used inside the method definitions associated with the #:methods keyword, binds local-id to the generic for method-id. This form is useful for method specializations to use generic methods (as opposed to the local specialization) on other values.

Using the define/generic form outside a #:methods specification in struct (or define-struct) is an syntax error.


> (define-generics printable
    (gen-print printable [port])
    (gen-port-print port printable)
    (gen-print* printable [port] #:width width #:height [height]))
> (define-struct num (v)
    #:methods gen:printable
    [(define/generic super-print gen-print)
     (define (gen-print n [port (current-output-port)])
       (fprintf port "Num: ~a" (num-v n)))
     (define (gen-port-print port n)
       (super-print n port))
     (define (gen-print* n [port (current-output-port)]
                         #:width w #:height [h 0])
       (fprintf port "Num (~ax~a): ~a" w h (num-v n)))])
> (define-struct bool (v)
    #:methods gen:printable
    [(define/generic super-print gen-print)
     (define (gen-print b [port (current-output-port)])
       (fprintf port "Bool: ~a"
                (if (bool-v b) "Yes" "No")))
     (define (gen-port-print port b)
       (super-print b port))
     (define (gen-print* b [port (current-output-port)]
                         #:width w #:height [h 0])
       (fprintf port "Bool (~ax~a): ~a" w h
                (if (bool-v b) "Yes" "No")))])
> (define x (make-num 10))
> (gen-print x)

Num: 10

> (gen-port-print (current-output-port) x)

Num: 10

> (gen-print* x #:width 100 #:height 90)

Num (100x90): 10

> (define y (make-bool #t))
> (gen-print y)

Bool: Yes

> (gen-port-print (current-output-port) y)

Bool: Yes

> (gen-print* y #:width 100 #:height 90)

Bool (100x90): Yes

> (define/contract make-num-contracted
    (-> number?
          [gen-print (->* (printable?) (output-port?) void?)]
          [gen-port-print (-> output-port? printable? void?)]
          [gen-print* (->* (printable? #:width exact-nonnegative-integer?)
                           (output-port? #:height exact-nonnegative-integer?)
> (define z (make-num-contracted 10))
> (gen-print* z #:width "not a number" #:height 5)

make-num-contracted: contract violation

 expected: exact-nonnegative-integer?

 given: "not a number"

 in: the #:width argument of

     the gen-print* method of

     the range of





         (->* (printable?) (output-port?) void?))


         (-> output-port? printable? void?))










 contract from:

      (definition make-num-contracted)

 blaming: top-level

 at: eval:13.0