In Common Lisp, structures are thought as rigid and low-level records. They don't have fancy dynamic features.
What you can do with structures is to defined a new structure type which inherits from another one. There is single inheritance available.
To handle dynamic extensibility, a typical way is to add a property list slot to a structure. See the answer of Joshua.
Then there is the Common Lisp Object System, which provides multiple inheritance and you can change classes at runtime. So you can add a slot to a class and the instances of that class update themselves. You can also change the class of an object and slots may get added or deleted. Still, typically all instances of a class will have the same set of slots. Again, one sees that a slot with a property list can be added and used for extensibility.
There are other object systems for Common Lisp, which can easily add slots on a per-instance base. But it is usually too much to use them just for that, since they are quite a bit more powerful.
With CLOS and the Meta-object protocol one can try to hide it. Here I am using LispWorks:
We define a mixin class for our properties:
(defclass property-mixin ()
((plist :initform nil))
#+lispworks
(:optimize-slot-access nil))
Setting and reading the properties:
(defmethod set-property ((object property-mixin) key value)
(setf (getf (slot-value object 'plist) key) value))
(defmethod get-property ((object property-mixin) key)
(getf (slot-value object 'plist) key))
Now we write methods to make SLOT-VALUE
accepting our property names:
(defmethod (setf clos:slot-value-using-class)
(value (class standard-class) (object property-mixin) slot-name)
(declare (ignorable class))
(if (slot-exists-p object slot-name)
(call-next-method)
(progn
(set-property object slot-name value)
value)))
(defmethod clos:slot-value-using-class ((class standard-class)
(object property-mixin)
slot-name)
(declare (ignorable class))
(if (slot-exists-p object slot-name)
(call-next-method)
(get-property object slot-name)))
Example. We define an automobile class with two slots:
(defclass automobile (property-mixin)
((company :initarg :company)
(motor :initarg :motor))
#+lispworks
(:optimize-slot-access nil))
Now an instance:
CL-USER 45 > (setf a6 (make-instance 'automobile :company :audi :motor :v6))
#<AUTOMOBILE 402005B47B>
We can get a normal slot value:
CL-USER 46 > (slot-value c1 'motor)
:V6
Let's write to a slot which does not exist, but will be added to our property list:
CL-USER 47 > (setf (slot-value a6 'seats) 4)
4
We can get the value back:
CL-USER 48 > (slot-value c1 'seats)
4
node
? In other words, is there a way to do(make-node 'some-label :one 1 :two 2) => (SOME-LABEL :ONE 1 :TWO 2)
, instead of(SOME-LABEL (:ONE 1 :TWO 2))
? – Searchlight