[racket] Overriding methods in Racket classes
OK using define-local-member-name works, see case 1 below, but it
seems it would be much simpler if there was a form define/inheritable
which made the method accessable within the class body where it was
defined and in the sub-class bodies only. (see case 2 below)
i.e. no wrapping in a let that returned multiple values etc.
Is there some reason there isn't such a form define/inheritable ?
===================================
Case 1 (using define-local-member-name)
=================================
#lang racket
(define-values (fish% picky-fish%)
(let ()
(define-local-member-name grow)
(define fish% (class object%
(init size) ; initialization argument
(define current-size size) ; field
(super-new) ; superclass initialization
(define/public (get-size)
current-size)
(define/public (grow amt)
(set! current-size (+ amt current-size)))
(define/public (eat other-fish)
(grow (send other-fish get-size)))))
(define picky-fish% (class fish% (super-new)
(define/override (grow amt)
(super grow (* 3/4 amt)))))
(values fish% picky-fish%)))
(define joe-the-minnow (new fish% [size 2]))
(define bud-the-minnow (new fish% [size 2]))
(define big-al-the-pike (new fish% [size 10]))
(define picky-selma (new picky-fish% [size 5]))
(send picky-selma eat joe-the-minnow)
(send picky-selma get-size)
;;this now correctly fails
;(send bud-the-minnow grow 5)
====================================
(Case 2 using a hypothetical define/inheritable)
====================================
#lang racket
(define fish% (class object%
(init size)
(define current-size size)
(super-new)
(define/public (get-size)
current-size)
(define/public (grow amt)
(set! current-size (+ amt current-size)))
(define/inheritable (eat other-fish) ;;;hypothetical define/inheritable
(grow (send other-fish get-size)))))
(define picky-fish% (class fish% (super-new)
(define/override (grow amt)
(super grow (* 3/4 amt)))))
(define joe-the-minnow (new fish% [size 2]))
(define bud-the-minnow (new fish% [size 2]))
(define big-al-the-pike (new fish% [size 10]))
(define picky-selma (new picky-fish% [size 5]))
(send picky-selma eat joe-the-minnow)
(send picky-selma get-size)
Thanks,
Harry Spier
On 1/3/13, Asumu Takikawa <asumu at ccs.neu.edu> wrote:
> On 2013-01-03 17:01:54 -0500, Harry Spier wrote:
>> In Racket is it possible to override a non-public method?
>>
>> [...]
>>
>> Apologies if I've missed something obvious but I've just started going
>> through the Classes and Objects documentation. I can see where you
>> can declare a method public and overridable, or public and not
>> overridable, but I don't see a declaration for a method to be private
>> to the outside world but public and overridable to its sub-classes.
>
> You can use local member names to accomplish this. It effectively makes
> certain method names lexically scoped. Here is an example:
>
> #lang racket
>
> (define-values (bomb% detonator%)
> (let ()
> ;; lexically scoped method name
> (define-local-member-name detonate)
> (values
> (class object%
> (super-new)
> ;; public only while the name is in scope
> (define/public (detonate)
> (displayln "boom!")))
> (class object%
> (super-new)
> (init-field bomb)
> (define/public (trigger)
> (send bomb detonate))))))
>
> ;; error since `detonate` not in scope
> ;(send (new bomb%) detonate)
>
> ;; works
> (send (new detonator% [bomb (new bomb%)]) trigger)
>
> Using local member names, the "outside world" is wherever the name is
> not bound. If it is in scope, you can invoke it, override it, etc and
> your method declarations are done normally.
>
> Cheers,
> Asumu
>