On Wed, Aug 12, 2020 at 7:19 PM Siyuan Chen <chanse...@gmail.com> wrote:

> 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)
>

No, traits can contain fields, which are mutable, so a trait can manage
state.

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.
>    ```
>

Right, one trait cannot override another's definitions. One thing you could
do instead is use `trait-exclude` to remove the definition of `needed-item`
from `secure-trait` before linking a trait (like `locked-needed-trait`, but
using `define/public` instead of `define/override`) that defines the
`needed-item` method. But if you do that, I think there's no way to chain
to the original definition. (I haven't tried any of this, but that's what I
get from the docs.)

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 ?
>

I'm not sure, but I think the answer is no. If we distinguish "method
names" from "method slots" (or "vtable slots", to put it in terms of one
implementation strategy), then I think this example requires the ability to
change a method name to refer to a new method slot (but only for
subclasses; existing references point to the original slot), and I don't
think Racket's class system offers that ability. In particular, I think
that feature is not expressible using `inner`, although `inner` does
require a more complicated notation of "method slot" than a Java-style
class system. Anyway, that feature sounds maybe more dangerous than
worthwhile.

But if you know that you might want to apply the secure mixin multiple
times with different needed items, then there are other ways to write that
code. One is to parameterize the mixin by the needed item directly:

  ;; make-secure-mixin : Item -> (impl/c door<%>) -> (impl/c door<%>)
  (define (make-secure-mixin the-needed-item)
    (mixin (door<%>) (door<%>)
      (super-new)
      (define/override (can-open p)
        (println "secure-mixin can-open")
        (cond [(send p has-item the-needed-item) ....]
              [else ....]))))

  (define locked-needed-mixin (make-secure-mixin the-key))
  (define magic-needed-mixin (make-secure-mixin the-spell-book))

Another is to parameterize `secure-mixin` over the *name* of the auxiliary
hook method, using `define-member-name` etc. That avoids the problem of
needing the same *name* to refer to different "slots" at different points
in time; instead, just use two different names. But IIRC, if you read the
APLAS paper on traits in Racket (Flatt et al), you discover that `trait` is
just syntactic sugar for this kind of member-name manipulation. So traits
are this design pattern turned into a linguistic construct.

Ryan

-- 
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 racket-users+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/racket-users/CANy33q%3DWc594hxD3Y6jNXd05FXZESbX7h2T6Zokh-w%3DPNGjk2A%40mail.gmail.com.

Reply via email to