Can anybody think of any situations where this overloading would cause problems?
Admittedly, I can't think of any, but the scope of the change makes me uncomfortable. For any function f, (sref f v k) turns into (f k v)? Seems heavy-handed.
An alternative is to use defset to special-case on prototypes, but that relies on knowing the name of your prototype object. So, you'd have to make the macro explicitly assign to a name and defset that, which is kind of ugly:
(mac defproto (name parent . attrs)
(w/uniq lookup
`(let ,lookup (obj ,@attrs)
(= ,name (fn (attr . args)
(if args
(= (,lookup attr) (car args))
(or (,lookup attr)
((only .attr) ,parent)))))
(defset ,name (attr)
(w/uniq g
(list (list g attr)
`(,',name ,g)
`(fn (val) (,',name ,g val)))))
,name)))
arc> (defproto a nil x "foo")
#<procedure: a>
arc> (defproto b a y "bar")
#<procedure: b>
arc> (defproto c b z "qux")
#<procedure: c>
arc> (map [list _!x _!y _!z] (list a b c))
(("foo" nil nil) ("foo" "bar" nil) ("foo" "bar" "qux"))
arc> (= b!x "changed")
"changed"
arc> (list a!x b!x c!x)
("foo" "changed" "changed")
By separating out the setter logic, you could address the (a 'x 10) issue:
(mac defproto (name parent . attrs)
(w/uniq (lookup attr-setter)
`(let ,lookup (obj ,@attrs)
(= ,name
(fn (attr (o default))
(or (,lookup attr default)
((only [_ attr default]) ,parent))))
(= ,attr-setter
(fn (attr val)
(= (,lookup attr) val)))
(defset ,name (attr)
(w/uniq g
(list (list g attr)
`(,',name ,g)
`(fn (val) (,',attr-setter ,g val)))))
,name)))
arc> (defproto a nil x 5)
#<procedure:zz>
arc> (a 'x)
5
arc> (a 'x 10)
5
arc> (a 'y)
nil
arc> (a 'y 10)
10
arc> (a 'y)
nil
I'm not sure how to address the issue of using fns as protoypes. As Arc's type system stands, there may not be a much better way.