From: Kenneth Tilton on
There's no way to funcall a setter! FUNCTION does not take variables!

Python can do it!

kt
From: Madhu on

* Kenneth Tilton <4af5624a$0$31273$607ed4bc(a)cv.net> :
Wrote on Sat, 07 Nov 2009 07:04:30 -0500:

| There's no way to funcall a setter! FUNCTION does not take variables!

So create a funcallable from the `setter's' name and funcall it! Here's
an implementation that even compiles the setter and caches it!

(defvar *setter-cache* (make-hash-table :test #'eq))

(defun find-or-make-setter (accessor-symbol
&optional (accessor-cache *setter-cache*))
(check-type accessor-symbol symbol)
(check-type accessor-cache hash-table)
(or (gethash accessor-symbol accessor-cache)
(setf (gethash accessor-symbol accessor-cache)
(multiple-value-bind
(vars vals store-vars writer-form reader-form)
(get-setf-expansion (list accessor-symbol 'object))
(declare (ignore reader-form))
;;(warn "computing ~A." accessor-symbol)
(let* ((bindings
(nconc
(pairlis vars (mapcar 'list vals))
(pairlis store-vars (list '(new-value)))))
(form `(lambda (new-value object)
(let ,bindings ,writer-form))))
(compile nil form))))))


;; Example Use
(defstruct foo a)
(defvar $a (make-foo))
(funcall (find-or-make-setter 'foo-a) 10 $a) ; => #S(FOO :A 10)

--
Madhu
From: Pascal J. Bourguignon on
Kenneth Tilton <kentilton(a)gmail.com> writes:

> There's no way to funcall a setter! FUNCTION does not take variables!
>
> Python can do it!

CL too.


C/USER[90]> (defvar *store* nil)
*STORE*
C/USER[91]> (defun (setf store) (newval) (setf *store* newval))
(SETF STORE)
C/USER[92]> (defun store () *store*)
STORE
C/USER[93]> (funcall (fdefinition '(setf store)) 42)
42
C/USER[94]> (store)
42
C/USER[95]> (funcall (fdefinition '(setf store)) 1)
1
C/USER[96]> (store)
1
C/USER[97]>


(setf store) is a setter.

On the other hand, while you can write (setf (car x) v),
(setf car) may be not defined: SETF can have specific knowledge of
some places without a need for an external setter.

--
__Pascal Bourguignon__
From: Kenneth Tilton on
Pascal J. Bourguignon wrote:
> Kenneth Tilton <kentilton(a)gmail.com> writes:
>
>> There's no way to funcall a setter! FUNCTION does not take variables!
>>
>> Python can do it!
>
> CL too.
>
>
> C/USER[90]> (defvar *store* nil)
> *STORE*
> C/USER[91]> (defun (setf store) (newval) (setf *store* newval))
> (SETF STORE)
> C/USER[92]> (defun store () *store*)
> STORE
> C/USER[93]> (funcall (fdefinition '(setf store)) 42)

Ah, silly me, I looked at fdefinition but didn't Get It.

thx,kt
From: Kenneth Tilton on
Madhu wrote:
> * Kenneth Tilton <4af5624a$0$31273$607ed4bc(a)cv.net> :
> Wrote on Sat, 07 Nov 2009 07:04:30 -0500:
>
> | There's no way to funcall a setter! FUNCTION does not take variables!
>
> So create a funcallable from the `setter's' name and funcall it! Here's
> an implementation that even compiles the setter and caches it!
>
> (defvar *setter-cache* (make-hash-table :test #'eq))
>
> (defun find-or-make-setter (accessor-symbol
> &optional (accessor-cache *setter-cache*))
> (check-type accessor-symbol symbol)
> (check-type accessor-cache hash-table)
> (or (gethash accessor-symbol accessor-cache)
> (setf (gethash accessor-symbol accessor-cache)
> (multiple-value-bind
> (vars vals store-vars writer-form reader-form)
> (get-setf-expansion (list accessor-symbol 'object))
> (declare (ignore reader-form))
> ;;(warn "computing ~A." accessor-symbol)
> (let* ((bindings
> (nconc
> (pairlis vars (mapcar 'list vals))
> (pairlis store-vars (list '(new-value)))))
> (form `(lambda (new-value object)
> (let ,bindings ,writer-form))))
> (compile nil form))))))

"compile"? Calm down!

kt