Search code examples
racketmixinsparameterized

mixin: method was referenced in definition, but is not in any of the from-interfaces


I have read the Racket guide 13.7.3 Parameterized Mixins

I use Parameterized Mixins to create a class good-eat-fish% from fish%

(define fish-interface
  (interface () eat get-size))

(define fish%
  (class* object% (fish-interface)
    (init size)
    (super-new)
    (define current-size size)
    (define/public (get-size) current-size)
    (define/public (eat other)
      (set! current-size (+ current-size (send other get-size))))))

(define (good-eat-mixin member-name)
  (define eat member-name)
  (mixin () ()
    (inherit eat)
    (define/public (good-eat y)
      (eat y) (eat y))))

(define good-eat-fish%
  ((good-eat-mixin (member-name-key eat)) fish%))

When I run the code the following error is raised:

"mixin: method was referenced in definition, but is not in any of the from-interfaces
  method name: eat
  from-interfaces:"

Does this error message indicate that there's no eat method?

If I change the code to

(define (good-eat-mixin member-name)
  (define eat member-name)
  (mixin (interface () eat) (interface () eat good-eat)
    (inherit eat)
    (define/public (good-eat y)
      (eat y) (eat y))))

I get this error:

interface: bad syntax in: interface

Unfortunately, I don't know why

interface () eat) 

is bad syntax.


Solution

  • For the first problem: mixins enforce a few checks for misuse, and you're running across them. For example, if you just do:

    (mixin () ()
      (inherit eat)
      (define/public (good-eat y)
        (eat y) (eat y)))
    

    then the system detects that the code is trying to depend on an eat method that isn't a part of the mixin's declared interface. Your second attempt is closer, but you need extra parens. e.g., from

    (mixin (interface () eat) (interface () eat good-eat)
      (inherit eat)
      (define/public (good-eat y)
        (eat y) (eat y)))
    

    to:

    (mixin ((interface () eat)) ((interface () eat good-eat))
      (inherit eat)
      (define/public (good-eat y)
        (eat y) (eat y)))
    

    Give names to the interfaces so that this is easier to see:

    (define eater<%> (interface () eat))
    (define good-eater<%> (interface () good-eat))
    ...
    (mixin (eater<%>) (good-eater<%>)
      ...)
    

    Here's an example:

    #lang racket
    
    (define eater<%> (interface () eat))
    (define good-eater<%> (interface () good-eat))
    
    (define fish%
      (class* object% (eater<%>)
        (init size)
        (super-new)
        (define current-size size)
        (define/public (get-size) current-size)
        (define/public (eat other)
          (set! current-size (+ current-size (send other get-size))))))
    
    (define fish-interface
      (interface () eat get-size))
    
    (define good-eat-mixin
      (mixin (eater<%>) (good-eater<%>)
        (inherit eat)
        (super-new)
        (define/public (good-eat y)
          (eat y) (eat y))))
    
    (define good-eat-fish%
      (good-eat-mixin fish%))
    
    (define f1 (new good-eat-fish% [size 42]))
    (define f2 (new good-eat-fish% [size 16]))
    (send f1 eat f2)
    (send f1 good-eat f2)
    (send f1 get-size)
    

    (I stripped out the member key stuff out of your example, just to simplify.)

    I believe the class system in racket/class is nominal rather than structural.