[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Initial comments & questions

This page is part of the web mail archives of SRFI 53 from before July 7th, 2015. The new archives for SRFI 53 contain all messages, not just those from before July 7th, 2015.



Sorry, this was a mix of two different ideas with a bug.  First is the
straightforward syntax-rules implementation via temp variables:

  (define-syntax with-slots
    (syntax-rules ()
      ((with-slots () obj . body) (begin . body))
      ((with-slots (slot1 slot2 ...) obj . body)
       (let ((slot1 (slot-ref obj 'slot1)))
         (with-slots (slot2 ...) obj body)))))

which is what the previous post ended up being.  This has two problems:

1) it doesn't reflect updates to the object's slots, via slot-set! or
other procedures which may mutate the object between the binding and the
reference:

  (with-slots (a b c) my-obj (slot-set! my-obj 'a 5) (+ a b c))
  => 111

2) it doesn't let us use CL-style setf:

;; quick setf implementation

(define (slot-set! obj slot val)
  (vector-set! obj (case slot ((a) 0) ((b) 1) ((c) 2) ((d) 3)) val))

(define (compute-setter proc)
  (cond ((eq? proc car) set-car!)
        ((eq? proc vector-ref) vector-set!)
        ((eq? proc slot-ref) slot-set!)))

(define-syntax setf
  (syntax-rules ()
    ((setf (proc args ...) val)
     ((compute-setter proc) args ... val))
    ((setf x val) (set! x val))))

;; my-obj is unchanged
(with-slots (a b) my-obj (setf a (+ a b)))

The following version of with-slots-computation instead of using temp
variables translates the symbols to direct calls to slot-ref:

(define-syntax-computation with-slots-computation
  (computation-rules ()
    ((with-slots-computation () obj . body)
     (syntax-return (begin . body)))
    ((with-slots-computation (slot1 slot2 ...) obj . body)
     (syntax-do (inner1 <- (with-slots-computation (slot2 ...) obj . body))
       (syntax-replace slot1 (slot-ref obj 'slot1) inner1)))))

(syntax-inspect (with-slots-computation (a) my-obj (+ a 1)))
=> (begin (+ (slot-ref my-obj 'a) 1))

And now intermediate mutations and setf work:

(with-slots (a b c) my-obj (setf a (+ a b c)))
my-obj
#(111 10 100 1000)

But after this the previous example re-binding a fails:

(with-slots (a b) my-obj (let ((a 5)) (add a b)))

Error: invalid syntax (let (((...) 5)) (add (slot-ref my-obj (...)) (slot-ref my-obj (...)))).

We're blindly replacing "a" anywhere in the expression, even in a let
binding.  To fix this we'd need to resort to code walking techniques,
which really need the syntax-expand form Taylor suggested.  However, so
long as you don't use the bound slot names for any other purpose in the
literal, non-expanded body of the expression you're fine :)

[Note: everything is still slow due to memory constraints and thrashing.
I have no idea how it's sucking up >200MB of my RAM.]

-- 
Alex