Dear Ryan,

Thanks for your solution, it works nicely!

But I still have some questions:

For this particular problem of LockedMagicDoor, we can use `trait` to solve
the `mixin` problem, but can we use the same method for more general
problems?

Since traits and mixins are essentially different, they may not mimic each
other...

IMO, they are at least 2 differences:

1. Traits can not have states, but mixin can.

   For example, if the `secure-trait`,  `locked-needed-trait`, and
`magic-needed-trait` have mutable states, then you can not use `trait`.  (A
workaround may be to convert `trait` to `mixin` first and then compose a
"state" mixin. But this will cause the same problem of name colliding,
because `mixin` does not support renaming)

2. `trait-sum` is symmetric, it does not support overriding.

   For example, in your solution:

   ```
   (define locked-mixin
     (trait->mixin
      (trait-rename (trait-sum secure-trait locked-needed-trait)
                    needed-item needed-item/locked)))
   ```

   To construct `locked-mixin`, you `trait-sum` the  `secure-trait` and
 `locked-needed-trait`, but what if there is a default implementation of
`needed-item` in the `secure-trait`? We even hope the `locked-needed-trait`
can delegate to `super`, something like:

   ```
   (define locked-needed-trait
     (trait
      (define/override (needed-item)
        (println "locked-needed-mixin neededItem")
        (super needed-item))))  ;; We want to call super.
   ```

The key question is:

Does the current racket class system have the equivalent capabilities of
MIXEDJAVA?

More concretely, we know that Racket supports mixin, but Racket's `mixin`
is slightly different from MIXEDJAVA. This is because we seemingly can not
implement LockMagicDoor by using only `mixin-form` (Is this by design? I
heard that there are some historical origins of MIXEDJAVA and MzScheme).

But Racket supports two additional features, i.e.  `inner` and `trait`,
 which are not in MIXEDJAVA.

Consequently,  I'm curious about whether there is any design pattern in
Racket that can simulate the semantics of MIXEDJAVA ?

Thanks.

Best regards,
Siyuan Chen


On Tue, Aug 11, 2020 at 10:09 PM Ryan Culpepper <[email protected]>
wrote:

> I don't know of a way to solve that problem using the Racket class system
> alone, but here is a solution that uses traits instead, which allow you to
> rename the hook methods after the fact so they don't collide.
>
>   ;; ....
>   (require racket/trait)
>
>   (define secure-trait
>     (trait
>      (inherit needed-item)
>      (define/override (can-open p)
>        (println "secure-mixin can-open")
>        (define item (needed-item))
>        (cond
>          ((not (send p has-item item)) (printf "You don't have the Key
> ~v\n" item)
>           #f)
>          (else (printf "Using Key... ~v\n" item)
>                (super can-open p))))))
>
>   (define locked-needed-trait
>     (trait
>      (define/public (needed-item)
>        (println "locked-needed-mixin neededItem")
>        the-key)))
>
>   (define magic-needed-trait
>     (trait
>      (define/public (needed-item)
>        (println "magic-needed-mixin neededItem")
>        the-spell-book)))
>
>   (define locked-mixin
>     (trait->mixin
>      (trait-rename (trait-sum secure-trait locked-needed-trait)
>                    needed-item needed-item/locked)))
>
>   (define magic-mixin
>     (trait->mixin
>      (trait-rename (trait-sum secure-trait magic-needed-trait)
>                    needed-item needed-item/magic)))
>   ;; ....
>
> Ryan
>
>
> On Sun, Aug 9, 2020 at 11:12 PM Siyuan Chen <[email protected]> wrote:
>
>> Hi all,
>>
>> Recently I read the paper "Classes and Mixins" by Matthew Flatt, Shriram
>> Krishnamurthi and Matthias Felleisen.
>>
>> In this paper, the authors presented MIXEDJAVA.
>>
>> In MIXEDJAVA,
>>
>>> A programmer implements mixins in exactly the same
>>> way as a derived class, except that the programmer cannot
>>> rely on the implementation of the mixin's superclass, only
>>> on its interface. We consider this an advantage of mixins
>>> because it enforces the maxim "program to an interface, not
>>> an implementation".
>>>
>> It is very close to the mixin form in Racket, because we can specific
>> interface in the mixin form:
>>
>> ```
>> (mixin (interface-expr ...) (interface-expr ...)
>>   class-clause ...)
>> ```
>>
>> In Chapter 3, they also introduced an example (a maze adventure game, I
>> called it LockedMagicDoor) which uses the system.
>>
>> My question is:
>>
>> Is it possible to implement LockedMagicDoor in Racket?
>>
>>
>> I did some experiments but failed.
>>
>> See following code (or
>> https://gist.github.com/chansey97/aecffabb2885c83fa040ba677bde5de4):
>>
>> ```
>> #lang racket
>>
>> (define the-key 'the-key)
>> (define the-spell-book 'the-spell-book)
>>
>> (define person%
>>   (class object%
>>     (init-field items h)
>>     (super-new)
>>
>>     (define/public (has-item item)
>>       (member item items))
>>
>>     (define/public (height)
>>       h)
>>     ))
>>
>> (define door<%> (interface () can-open can-pass))
>>
>> (define door-mixin
>>   (mixin () (door<%>)
>>     (super-new)
>>
>>     (define/public (can-open p)
>>       (println "door% can-open")
>>       #t)
>>
>>     (define/public (can-pass p)
>>       (println "door% can-pass")
>>       #t)
>>     ))
>>
>> (define secure-door<%> (interface (door<%>) needed-item))
>>
>> (define secure-mixin
>>   (mixin (door<%>) (secure-door<%>)
>>     (super-new)
>>
>>     (define/public (needed-item) ;; error??
>>       (println "secure-mixin needed-item")
>>       #f)
>>
>>     (define/override (can-open p)
>>       (println "secure-mixin can-open")
>>       (define item (needed-item))
>>       (cond
>>         ((not (send p has-item item)) (printf "You don't have the Key
>> ~v\n" item)
>>                                       #f)
>>         (else (printf "Using Key... ~v\n" item)
>>               (super can-open p))))
>>     ))
>>
>> (define locked-needed-mixin
>>   (mixin (secure-door<%>) (secure-door<%>)
>>     (super-new)
>>     (define/override (needed-item)
>>       (println "locked-needed-mixin neededItem")
>>       the-key)
>>     ))
>>
>> (define magic-needed-mixin
>>   (mixin (secure-door<%>) (secure-door<%>)
>>     (super-new)
>>     (define/override (needed-item)
>>       (println "magic-needed-mixin neededItem")
>>       the-spell-book)
>>     ))
>>
>> (define door%
>>   (door-mixin object%))
>>
>> (define locked-mixin (compose locked-needed-mixin secure-mixin))
>> (define magic-mixin (compose magic-needed-mixin secure-mixin))
>>
>> (define locked-magic-mixin (compose locked-mixin magic-mixin))
>> (define locked-magic-door% (locked-magic-mixin door%))
>>
>> (define door (new locked-magic-door%))
>> (send door can-open (new person% [items (list the-key the-spell-book)] [h
>> 0.5]))
>>
>> ; class*: superclass already contains method
>> ;   superclass: #<class:...agic-door-failed.rkt:62:2>
>> ;   method name: needed-item
>> ;   class name: ...agic-door-failed.rkt:36:2
>>
>> ```
>>
>> The problem is how to implement `secure-mixin`?
>>
>> Notice that since the `secure-mixin` is mixed into `locked-magic-door%`
>> twice, there will be two `needed-item` methods in the inheritance chain, so
>> they are naming conflict.
>>
>> However in MIXEDJAVA, they do not conflict:
>>
>>> Specifically, a composition m1 compose m2 contains two methods named
>>> x if both m1 and m2 declare x and m1's inheritance interface does not
>>> contain x. Both x methods are accessible in an instance of the composite
>>> mixin since the object can be viewed specifically as an instance of m1
>>> or m2.
>>>
>> Can someone help me? (e.g. make some changes to this code above and let
>> it work in Racket)
>>
>> Very thanks.
>>
>>
>> I also attempt to use Inner to simulate the behavior of MIXEDJAVA:
>>
>> ```
>> (define secure-mixin
>>   (mixin (door<%>) (secure-door<%>)
>>     (super-new)
>>
>>     (define/pubment (needed-item)
>>       (println "secure-mixin needed-item")
>>       #f)
>>
>>     (define/override (can-open p)
>>       (println "secure-mixin can-open")
>>       (define item (inner #f needed-item))
>>       (cond
>>         ((not (send p has-item item)) (printf "You don't have the Key
>> ~v\n" item)
>>                                       #f)
>>         (else (printf "Using Key... ~v\n" item)
>>               (super can-open p))))
>>     ))
>>
>> (define locked-needed-mixin
>>   (mixin (secure-door<%>) (secure-door<%>)
>>     (super-new)
>>     (define/augride (needed-item)
>>       (println "locked-needed-mixin neededItem")
>>       the-key)
>>     ))
>>
>> (define magic-needed-mixin
>>   (mixin (secure-door<%>) (secure-door<%>)
>>     (super-new)
>>     (define/augride (needed-item)
>>       (println "magic-needed-mixin neededItem")
>>       the-spell-book)
>>     ))
>> ```
>>
>> But still failed:
>>
>> ; class*: superclass already contains method
>> ;   superclass: #<class:...y-pubment-failed.rkt:62:2>
>> ;   method name: needed-item
>>
>> See https://gist.github.com/chansey97/264d3435a8f506153709cc9804227fdf
>>
>> PS: I also tried `overment` and `augment` for the `needed-item` in
>> `secure-mixin`, but failed as well (although the error messages are
>> different).
>>
>>
>> IMO, it seems that `Inner` can be used to simulate the behavior of
>> MIXEDJAVA, but I don't know how to do it.
>>
>> Notice that in the paper, "Super and Inner — Together at Last!" by David
>> S. Goldberg, Robert Bruce Findler and Matthew Flatt, the authors originally
>> used `beta` and `java` to mark the methods, no need `pubment` a method
>> first. In that model, it may not be conflicting (just a very immature
>> opinion).
>>
>> So can we use the `Inner` to simulate the behavior of MIXEDJAVA?
>>
>>
>> Another question:
>>
>> In MIXEDJAVA, there is a `view` concept, which is very powerful.
>>
>> Can we get the corresponding equivalent in Racket?
>>
>> Very thanks.
>>
>>
>> Best regards,
>>
>> Siyuan Chen
>>
>>
>> --
>> You received this message because you are subscribed to the Google Groups
>> "Racket Users" group.
>> To unsubscribe from this group and stop receiving emails from it, send an
>> email to [email protected].
>> To view this discussion on the web visit
>> https://groups.google.com/d/msgid/racket-users/CAHWTsYnZCbRt2U%2Bt7JQPNt7rBNQAwSy8_4ycUqNkQ23ZOdncvQ%40mail.gmail.com
>> <https://groups.google.com/d/msgid/racket-users/CAHWTsYnZCbRt2U%2Bt7JQPNt7rBNQAwSy8_4ycUqNkQ23ZOdncvQ%40mail.gmail.com?utm_medium=email&utm_source=footer>
>> .
>>
>

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/racket-users/CAHWTsYk2envNNr1Rkrgyp-i5tHxrrkA5RS2UHDS3RDj7pWapjQ%40mail.gmail.com.

Reply via email to