[racket] Best practices for classes

From: Matthew Butterick (mb at mbtype.com)
Date: Sat Oct 4 13:16:10 EDT 2014

Actually it's probably better, as it prevents ambiguity about which
predicates 'class-instance' should meet. Unlike 'class-instance', the
expression '(class-instance)' starts with no predicates, so making '(list?
(class-instance))' true won't disrupt anything else. Thus, you can be
explicit about when it should behave as a class instance and when it should
behave as a list.


On Sat, Oct 4, 2014 at 9:50 AM, Matthew Butterick <mb at mbtype.com> wrote:

> I see your point. As a workaround, I suppose it's just as good to combine
> these ideas and use `prop:procedure` to hook into the `get-list` method.
> Then, instead of using 'class-instance' as a list, I can use  '(class-instance)',
> and things like (member val (class-instance)) and (map proc
> (class-instance)) will work as expected (= operating on the list inside the
> class instance).
>
>
>
> On Sat, Oct 4, 2014 at 8:13 AM, Robby Findler <robby at eecs.northwestern.edu
> > wrote:
>
>> There is no prop:list like that.
>>
>> Adding more prop:* features (like prop:list) has implications for code
>> that you cooperate with. In particular, when you get something that
>> answers #t to list?, then you can rest assured that calling 'car' or
>> it is a very simple operation (doesn't invoke unknown code, involves
>> just a pointer dereference and some simple checks in the machine,
>> etc). If we had a prop:list, then you wouldn't know those things and
>> thus you might have to treat simple list iterations with the same care
>> that you treat calling into unknown code (like it might grab a
>> continuation and return to you later etc).
>>
>> That said, I do think that our integration of generic operations and
>> our standard library deserves some more care and perhaps redesign to
>> make things hang together better. As it stands, we have some
>> conveniences, but they are limited by backwards compatibility concerns
>> (like the one in the previous paragraph). I have heard that some are
>> considering this as part of "racket2" but I don't know how far along
>> those plans are.
>>
>> Robby
>>
>>
>>
>> On Sat, Oct 4, 2014 at 10:01 AM, Matthew Butterick <mb at mbtype.com> wrote:
>> > Thank you. The `prop:procedure` works as hoped, in that the class
>> instance
>> > becomes usable in any form that takes a procedure (including things like
>> > map).
>> >
>> > The `prop:sequence` also works, but … what it seems I really want is
>> > `prop:list`, which AFAICT doesn't exist (?)
>> >
>> > The class I'm making is basically a list wrapped with some state. So in
>> > terms of the class interface, it would be very convenient to allow a
>> class
>> > instance to be used anywhere a list is used.
>> >
>> > The problem with `prop:sequence` is that now I have to use the special
>> > sequence versions of list functions, or convert to a list explicitly
>> with
>> > `sequence->list`. In terms of class interface, this isn't an improvement
>> > over just using a method like (send class-instance get-list).
>> >
>> >
>> >
>> > On Thu, Oct 2, 2014 at 7:43 PM, Alexander D. Knauth <
>> alexander at knauth.org>
>> > wrote:
>> >>
>> >> I don’t know if you can do it with generic interfaces (as in
>> >> racket/generic),
>> >> but you can make classes whose instances have struct-type properties
>> such
>> >> as prop:procedure and prop:sequence
>> >> (using interfaces as in racket/class, not racket/generic)
>> >>
>> >> #lang racket
>> >>
>> >> (define proc<%>
>> >>   (interface* ()
>> >>               ([prop:procedure
>> >>                 (lambda (this . args)
>> >>                   (send/apply this proc args))])
>> >>               proc))
>> >>
>> >> (define proc%
>> >>   (class* object% (proc<%>)
>> >>     (super-new)
>> >>     (define/public (proc x)
>> >>       (displayln "this is the proc method of proc%")
>> >>       x)))
>> >>
>> >> (define seq<%>
>> >>   (interface* ()
>> >>               ([prop:sequence
>> >>                 (lambda (this)
>> >>                   (send this get-sequence))])
>> >>               get-sequence))
>> >>
>> >> (define seq%
>> >>   (class* object% (seq<%>)
>> >>     (super-new)
>> >>     (define/public (get-sequence)
>> >>       (list 1 2 3))))
>> >>
>> >> > (define p (new proc%))
>> >> > (p 1)
>> >> this is the proc method of proc%
>> >> 1
>> >> > (define s (new seq%))
>> >> > (sequence-for-each displayln s)
>> >> 1
>> >> 2
>> >> 3
>> >>
>> >> On Oct 2, 2014, at 6:21 PM, Matthew Butterick <mb at mbtype.com> wrote:
>> >>
>> >> What's the best approach to:
>> >>
>> >> + defining a class whose instances can be used as procedures?
>> >>
>> >> (define ci (new proc-class%))
>> >> (ci arg arg2 ... )
>> >>
>> >> + ... whose instances can be used as lists (or at least support direct
>> >> iteration?)
>> >>
>> >> (define li (new listish-class%))
>> >> (for-each displayln li)
>> >> (map ci li)
>> >>
>> >> My intuition is "implement a generic interface..." But then it gets
>> hazy.
>> >>
>> >>
>> >>
>> >>
>> >> ____________________
>> >>  Racket Users list:
>> >>  http://lists.racket-lang.org/users
>> >>
>> >>
>> >
>> >
>> > ____________________
>> >   Racket Users list:
>> >   http://lists.racket-lang.org/users
>> >
>>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.racket-lang.org/users/archive/attachments/20141004/d5f910a9/attachment-0001.html>

Posted on the users mailing list.