Search code examples
schemeracket

Dynamic function call in Racket class combined with apply


TL;DR

What I'm looking for is a combination of the functions send/apply and dynamic-send. So that it finds a method of an object based on a symbol and unpacks a list of arguments.

Background and more info

For a project I am sending some "commands" trough the network with Racket's tcp-connect. At the receivers end this command should execute a method from a class and pass along its parameters.

Consider the following received 'message':

(define message (list 'set-switch! '3 'on))
(define method-name (car msg))  ;'set-switch!
(define parameters (cdr msg))   ;(list '3 'on)

And the following class:

(define light%
  (class object%
    (super-new)

    ...

    (define/public (set-switch! id mode)
      (vector-set! switches id mode))))

The problem now is that when executing this statement

(dynamic-send light-class method-name parameters)

it perfectly finds the method set-switch! but it calls it with only one parameter (list '3 'on).

The Racket docs mention those three functions for classes:

  • (send obj-expr method-id arg) which just executes a method of an object
  • (send/apply obj-expr method-id arg-list-expr) which executes a method AND unpacks the argument list
  • (dynamic-send obj method-name v) which finds a method-name based on a symbol

What I think I need is something like (dynamic-send/apply obj method-name arg-list-expr) which combines the last two mentioned.

Note: I know that I could just simply accept lists as parameters and use car and cdr in the functions itself to get the right values. But that's not what I want.


Solution

  • dynamic-send is a function (also known as procedure; e.g., car, vector-set!, +), so you can use apply:

    (apply dynamic-send light-class method-name parameters)
    

    Or even simply:

    (apply dynamic-send light-class message)
    

    The reason why send has the send/apply variant is that send is a form (also known as syntax; e.g., let, define, if), so apply doesn't work and hence send/apply is separately provided.