Thank you, Philip.  This is helpful.

On Fri, Jan 4, 2019 at 9:04 PM Philip McGrath <phi...@philipmcgrath.com>
wrote:

> I can't think of "something similar in functional Racket" (of course you
> can write purely functional programs with racket/class, but I know what you
> mean). I think it would be fairly easy to implement "something similar,"
> but I want to clarify what you have in mind, because augmentable methods
> don't quite match up with your pseudocode.
>
> The first point is that what you're doing seems more like "override" than
> "augment." Overriding methods is probably familiar to OOP people, but for
> illustration, here's a class that implements an overridable method:
> (define hi%
>   (class object%
>     (super-new)
>     (define/public (greet who)
>       (string-append  "Hi, " who))))
> When a subclass overrides the `greet` method, its implementation of the
> method gets called. The subclass can chose to call the superclass'
> implementation using `super`:
> (send (new (class hi%
>              (super-new)
>              (define/override (greet)
>                (list (super greet "Alice")
>                      (super greet "Bob")))))
>       greet)
> ;; -> '("Hi, Alice." "Hi, Bob.")
> Or, it can ignore the superclass's implementation altogether:
> (send (new (class hi%
>              (super-new)
>              (define/override (greet)
>                "Leave me alone!")))
>       greet)
> ;; -> "Leave me alone!"
>
> In contrast, with an augmentable method, control start's with the
> superclass' implementation. The subclass only gets control if/when the
> superclass uses `inner` to invoke its implementation:
> (define librarian%
>   (class object%
>     (super-new)
>     (define/pubment (goodnight)
>       (format "Goodnight, ~a."
>               (or (with-handlers ([exn:fail? (λ (e) #f)])
>                     (inner #f goodnight))
>                   "my someone")))))
>
> (send (new librarian%) goodnight)
> ;; -> "Goodnight, my someone."
> (send (new (class librarian%
>              (super-new)
>              (define/augment (goodnight)
>                "my love")))
>       goodnight)
> ;; -> "Goodnight, my love."
> A subclass can't use `augment` to escape the superclass:
> (send (new (class librarian%
>              (super-new)
>              (define/augment (goodnight)
>                (eprintf "We've got trouble!\n")
>                (error "Leave River City"))))
>       goodnight)
> ;; prints "We've got trouble!\n" to stderr
> ;; -> "Goodnight, my someone."
>
> Aside from that, neither `augment` nor `override` change the
> implementation of a method for immediate instances of the superclass,
> whereas your `before`, `after`, and `around` effectively `set!` the
> identifier greet to a different value than it had before. With that
> insight, it isn't difficult to make your pseudocode run:
>
> #lang racket
>
> (require rackunit
>          syntax/parse/define
>          racket/stxparam
>          (for-syntax syntax/transformer))
>
> (define-simple-macro (before name:id proc:expr ...+)
>   (set! name (compose name proc ...)))
> (define-simple-macro (after name:id proc:expr ...+)
>   #:with name* #`(compose #,@(reverse (syntax->list #'(name proc ...))))
>   (set! name name*))
> (define-syntax-parameter inner
>   (λ (stx) (raise-syntax-error #f "only allowed inside of around" stx)))
> (define-simple-macro (around name:id proc:expr)
>   (set! name
>         (let ([inner-name name])
>           (syntax-parameterize
>               ([inner (make-variable-like-transformer #'inner-name)])
>             proc))))
>
> (define (greet name)
>   (string-append  "Hi, " name "!"))
>
> (check-equal? (greet "Bob") "Hi, Bob!")
> (check-exn #rx"string-append" (λ () (greet 'Bob)))
>
> (before greet ~a)
> (check-equal? (greet 'Bob) "Hi, Bob!")
>
> (after greet list)
> (check-equal? (greet "Bob") '("Hi, Bob!"))
>
> (around greet
>         (λ (name)
>           (list "You asked me to say:"
>                 (inner name)
>                 "so I did.")))
>
> (check-equal? (greet 'Bob)
>               '("You asked me to say:"
>                 ("Hi, Bob!")
>                 "so I did."))
>
>
>
> -Philip
>
>
> On Fri, Jan 4, 2019 at 2:51 PM David Storrs <david.sto...@gmail.com>
> wrote:
>
>> Cool, thanks.  I'll look into generics more.  I've skimmed past them
>> before this but never really dug in.
>>
>> On Fri, Jan 4, 2019 at 1:46 PM Neil Van Dyke <n...@neilvandyke.org>
>> wrote:
>>
>>> I don't know what all is currently available for Racket[1], but two
>>> search keywords to slog through are "advice" and "aspect".
>>>
>>> Aspects and other framework-y interfaces can be good for extensibility
>>> of a system.  (But maybe try to make loosely-coupled reusable modules
>>> that don't need it, as much as practical.)  When you don't have an
>>> interface like that, but really-really need it, advice is sometimes a
>>> lifesaver.
>>>
>>> Separately, your particular example suggests that Racket's generics
>>> might do what you currently need to do.
>>>
>>>
>>> [1] It seems a lot of researchy/experimenty independent Racket stuff is
>>> not well-advertised.
>>>
>>> --
>> 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.
>> For more options, visit https://groups.google.com/d/optout.
>>
>

-- 
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.
For more options, visit https://groups.google.com/d/optout.

Reply via email to