[racket] Dynamically calling struct accessors/method names

From: Matthias Felleisen (matthias at ccs.neu.edu)
Date: Tue Sep 6 16:35:53 EDT 2011

On Sep 6, 2011, at 2:44 PM, Todd Bittner wrote:

> Actually, on pondering it for a few more minutes,  your original solution is sufficient for what I'm trying to do, which is to consolidate a lot of similar code into one common parent function, but it would be interesting to know how to call the function if I only had a string.  


> So, if for argument's sake, I had a file with a list of approved functions and one of them were 'posn-x', how would I take "posn-x" the string and turn into posn-x, the accessor call (or function call if it weren't a struct)?  

Here are three solutions, which I would use in the order v0, v1, and defined select: 

#lang racket

(struct posn (x y) #:transparent)

(define in 
  (open-input-string (string-append "posn-" (if (< (random 100) 50) "x" "y"))))

;; case next protects me from someone sending me a bad command 
(define (select.v0 in) 
  (define next (read in))
  (case next 
    [(posn-x) posn-x]
    [(posn-y) posn-y]
    [else (error 'select "attack!")]))

;; but if there are lots of commands and I need some speed, I'd create a hash table and associate symbols and functions 
(define (select.v1 in)
  "use some hash table")

;; if all of this fails, I may fall back on eval but only with trepidation 
(define-namespace-anchor top)

(define (select in)
  (eval (read in) (namespace-anchor->namespace top)))

;; test it all 
(define (foo a-posn a-selector)
  (a-selector a-posn))

(foo (posn 3 4) (select in))

Posted on the users mailing list.