Dear Ryan,

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

Thanks, I tested it.

You are right, traits can manage states.

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

Yes, "remove the definition of  `needed-item` from `secure-trait`" can
solve the name colliding problem, but there's no way to chain to the
original definition, because `needed-item` has been excluded.

Anyway, that feature sounds maybe more dangerous than worthwhile.
>

Do you mean the feature of MIXEDJAVA?

Why do you think it is dangerous?

As the paper says:

> We consider this an advantage of mixins
> because it enforces the maxim "program to an interface, not
> an implementation".

See the following code:

```
(define door<%> (interface () can-open can-pass))
(define secure-mixin
  (mixin (door<%>) (secure-door<%>) ; Inherit from a interface instead of
implementation
    (super-new)
    (define/public (needed-item)
      (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))))
    ))
```

Ideally, the developer of `secure-mixin` only needs to care about the
interface of the super-class, not the implementation.

Notice that the interface `door<%>` only has `can-open`  and `can-pass`, no
`needed-item`, so even if the implementation class of the `door<%>` has a
method with the same name (`needed-item`),  it should not cause conflicts.

It seems to be a good idea, IMO.

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

That's a good idea.

It is something like "prefer composition over inheritance" or "dependency
injection".

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
>

Nice.

Racket supports parameterizing identifiers in a `class`, that's an amazing
feature!

Best regards,

Siyuan Chen


On Thu, Aug 13, 2020 at 6:28 AM Ryan Culpepper <[email protected]>
wrote:

> On Wed, Aug 12, 2020 at 7:19 PM Siyuan Chen <[email protected]> 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 [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/racket-users/CAHWTsYkAd7dXdV1vn5GY_EKAKFy9pL8Po9uUCdpMf9Ym1K7HYg%40mail.gmail.com.

Reply via email to