Setting Attributes
Friday, January 14, 2011
One test of dynamic languages is to try and set attribute values on an object dynamically (e.g., without knowing until runtime which attributes need to be set). Below, we compare a simple example in Python, a fairly dynamic language, to Factor:
class Foo(object):
a, b, c = None, None, None
obj = Foo()
d = { "a" : 1, "b" : 2 }
obj.a = d.get("a")
obj.b = d.get("b")
obj.c = d.get("c")
print obj.a # 1
print obj.b # 2
print obj.c # None
We might directly translate the previous example to Factor code, using slot accessors to set attributes on the tuple instance:
TUPLE: foo a b c ;
foo new
H{ { "a" 1 } { "b" 2 } } {
[ "a" swap at >>a ]
[ "b" swap at >>b ]
[ "c" swap at >>c ]
} cleave
[ a>> . ] [ b>> . ] [ c>> . ] tri
But, it’s much better if you don’t need to know ahead of time which
attributes a class has (i.e., needing to write code to handle each
attribute). In Python, you might instead set each value dynamically
using the setattr
function:
for name, value in d.items():
setattr(obj, name, value)
We can use the set-slot-named word from the db.types vocabulary to do the same from Factor:
USING: assocs db.types fry kernel ;
: set-slots ( assoc obj -- )
'[ swap _ set-slot-named ] assoc-each ;
Note: the
set-slot-named
word (and theoffset-of-slot
word that it uses) should probably be moved to theslots
vocabulary.
We can simplify the previous example using our newly created set-slots
word and try it in the Factor listener:
IN: scratchpad TUPLE: foo a b c ;
IN: scratchpad foo new
IN: scratchpad H{ { "a" 1 } { "b" 2 } } over set-slots .
T{ foo { a 1 } { b 2 } }