I am having trouble figuring out how to represent the dta structures I want in a convenient way.
Here's a very stripped-down example, with comments indicating what I'm finding klunky.
(I found classes confusing -- should I be using them instead anyway?)
#lang racket/gui
; example for request for assistance
(require racket/generic)
(define-generics anything
(gdescription anything)
(gdescribe anything)
(gget-location anything)
(gset-location! anything l)
)
; Klunky that I need to define these, which are essentially renamings.
(define (description x) (gdescription x))
(define (describe x) (gdescribe x))
(define (get-location x) (gget-location x))
(define (set-location! x l) (gset-location! x l))
(struct location (name)
#:methods gen:anything
[
(define (gdescription loc) (format "~s" (location-name loc) ))
(define (gdescribe loc) (printf (description loc)))
]
)
(struct player (name [location #:auto #:mutable])
#:auto-value '()
#:methods gen:anything
[
(define (gdescription player)
(format "~s are in ~s\n"
(player-name player)
; Here's where I need description instead of gdescription.
; If I just call gdescription I end up with a recursive call to
; this function instead of the generic one, and
; it complains that [player-location player] isnt a player.
; Of course it isn't. It's a location.
(description [player-location player])
; And that's the only reason I'm defining gdescription
; as well as description.
)
)
(define (gdescribe player)
(printf (description player) )
)
; Do I really have to define set-location separately
; for each structure that uses gen:anything?
; Is there anything like extending an old structure when defining a new one?
; or mixins?
(define (gset-location! player x) (set-player-location! player x))
]
)
(define (place o l)
(set-location! o l)
)
(provide player describe location place)
One thing that I just noticed is that define/genmeth only works for the method that you are defining. If, for example, you changed player‘s describe to:
you will get an error, because description is bound to the immediate method that you define, which only handles player, not the generic description which can handle a location.
We could adjust the macro to fix this issue by making all calls generic.
My understanding is that generic calls are more expensive than direct calls, so it might not be a good idea to use define-meths when define/genmeth suffices.
I switched to classes from generics because I am migrating my code base to Typed Racket, and I found that classes work quite nicely for representing the notion of an abstract interface, or an abstract base class.
Now, as somebody told me, using classes for setting up an abstract interface is probably an overkill, but after playing around with some other options in Typed Racket I found that classes were the least clunky one for me.