Re: [racket-users] Can Racket implement LockedMagicDoor example of MIXEDJAVA?

2020-08-13 Thread Siyuan Chen
 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 
wrote:

> On Wed, Aug 12, 2020 at 7:19 PM Siyuan Chen  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`) th

Re: [racket-users] Can Racket implement LockedMagicDoor example of MIXEDJAVA?

2020-08-12 Thread Ryan Culpepper
On Wed, Aug 12, 2020 at 7:19 PM Siyuan Chen  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%3DWc594hxD3Y6j

Re: [racket-users] Can Racket implement LockedMagicDoor example of MIXEDJAVA?

2020-08-12 Thread Siyuan Chen
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 
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  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)
>>  

Re: [racket-users] Can Racket implement LockedMagicDoor example of MIXEDJAVA?

2020-08-11 Thread Ryan Culpepper
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  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: #
> ;   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
>> co

[racket-users] Can Racket implement LockedMagicDoor example of MIXEDJAVA?

2020-08-09 Thread Siyuan Chen
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: #
;   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: #
;   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 (alth