Colliflower ยป Silo

Silo is a library that makes accessing values by keys more generic.

Protocol

sget(object key &key)

Generic get function. Provides a uniform way to access properties of an object. The s stands for super, simple, or standard.

It is setfable as long as (setf sget) is defined as well, which it should be for mutable objects.

supdate(object key value &key)

Generic update function. Unlike (SETF SGET) it may or may not mutate OBJECT. Data structures should define one or both of (SETF SGET) and SUPDATE.

SUPDATE MUST return the updated object.

For immutable data structures, SUPDATE can be used to create updated data structures. It also works for prepending to lists such as plists or alists.

sdel(object key &key)

Generic delete function. Companion to sget and sset.

Like SSET it MUST return the object with changes.

ssetf(place key value &rest key-args &environment env)
Modify macro that sets a place equal to the result of SUPDATE.
slocation(place key &rest args &environment env)

SETF expander that uses SUPDATE to compute the new value to store in PLACE.

PLACE must be a SETFable place, and since this uses SUPDATE, it is safe for operations that don't mutate PLACE directly (such as prepending to a list).

define-sgetter((&whole lambda-list obj-spec key &rest params) place-expr &key declarations documentation)
Define SGET and (SETF SGET) for a place to use sget with.
rget(object &rest keys)

Recursive get. Calls sget for each key in turn from left to right.

As long as (SETF SGET) is defined for the final result, RGET is setfable.

rget-apply(object &rest keys+)
A combination of RGET and APPLY. It repeatedly calls SGET on successive results for each key, and the last argument is a list of keys to use.

Implementations

The following types have silo operations defined for them:

standard-object
sget and company on a standard object get and set a slot of the object.
hash-table
sget is equivalent to gethash for hash-tables, and sdel is equivalent to remhash.
array
sget is equivalent to aref for arrays (including vectors)
list
Lists are more complicated because there are multiple ways to use keys. By default silo assumes you want to access by the index in the list. However, you can also acces them as plists or alists, as described belos. described below access it as a plist and an alist. In general, if there are multiple ways to access a an object with keys, the recommended way is to use multiple dispatch on both the object referenced and the key, and create a special object for the key.

alists and plists

Since alists and plists are just lists with different semantics for the same underlying representation we needed a way to specify what type of list a list is. They way we do that is with special key objects for plists and alists (the default behavior for a list is to use the key as an index into the sequence).

One important thing to not is that for both plists and alists, while you can call (setf sget) in place to update a value already in the mapping, to add a new one you must use supdate or its companion (setf slocation), since the old list won't have a reference to the added key and value.

The special keys to access plists and alists are described below. Using a special object like this is the recommended way to deal with objects where there are multiple ways to access a key value.

plist-key(key-item)
Create a key to access an item in a plist
alist-key(item &key key (test (quote eql)))
Create a key to access values in alists with sget