How to set in object parameter list...

Started by oofoe, January 24, 2013, 01:00:00 AM

Previous topic - Next topic

oofoe

As I understand it, setf can not only set a variable, it can also set a "place", in this case, a position in a list. So I can create a simple class:

(new class 'Node)

(setq n (Node "test" '(5 3)))


If want to inspect or change the Node's coordinates, I can do this:

(println "location: " (n 2))
(setf (n 2) '(9 9))
(println "new location: " (n 2))


However, if I want to encapsulate the list access into the class, it doesn't work for setting:


(define (Node:where) ((self) 2))
(println "location: " (:where n))
(setf (:where n) '(14 3))
(println "same old location: " (:where n))


Is there any way to do anything like the above without having to define a separate getter and setter?



Thanks!
Testing can show the presence of bugs, but not their absence.

m i c h a e l

#1
I cannot think of a way of doing this, other than defining an accessor:
> (context (new Class 'Node))
Node
Node> (define (location lst) (if lst (setf (self 2) lst) (self 2)))
(lambda (lst)
 (if lst
  (setf (self 2) lst)
  (self 2)))
Node> (context MAIN)
MAIN
> (setq n (Node "test" '(5 3)))
(Node "test" (5 3))
> (:location n)
(5 3)
> (:location n '(14 3))
(14 3)
> n
(Node "test" (14 3))
> _


If you do want to set and get without writing an accessor, you could do the following to make the intention more clear:
> (context (new Class 'Node))
Node
Node> (constant 'name 1 'location 2)
2
Node> (context MAIN)
MAIN
> (setq n (Node "test" '(5 3)))
(Node "test" (5 3))
> (n Node:location)
'(5 3)
> (setf (n Node:location) '(14 3))
(14 3)
> n
(Node "test" (14 3))
> _


Personally, I prefer the former solution.



m i c h a e l

oofoe

#2
Thanks for taking a look Micheal!



Here's my latest stab at it. Although it could be better, it's not bad. It allows me to only specify a property name once, for instance. The major disadvantage is that if I want to set a property to nil, this won't do it since it uses a nil value as an indicator that you want to get the stored value of the property.


(define (property i value)  (if value (setf ((self) i) value))  ((self) i))

; h3. Node

(new Class 'Node)

(define (Node:title v)  (property 1 v))
(define (Node:where v)  (property 2 v))
(define (Node:colour v) (property 3 v))

; h2. Tests

(define (assert what pass)
  (println what "..." ('("FAILED" "OK") (if pass 1 0))))

(setq n (Node "Sample" '(9 4) "green" nil ""))

(assert "Title set" (= "Sample" (:title n)))
(:title n "Revised")
(assert "Title changed" (= "Revised" (:title n)))

(assert "Coordinates set" (= '(9 4) (:where n)))
(:where n '(44 99))
(assert "Coordinates changed" (= '(44 99) (:where n)))

(exit) ; Comment out for post-mortem debugging.


It would certainly be nice to hack a macro which would allow a friendlier property specification syntax, but so far this eludes me.
Testing can show the presence of bugs, but not their absence.