Template operations

One of the data structures provided by Arc is the template abstraction. Templates act somewhat like structure definitions. A template can be instantiated into a table that represents the structure as key-value pairs, where the keys can be considered field names in the structure, and the values are the values of the fields. A template defines a structure by defining the allowed keys, potentially with default values. A template is instantiated into a table by providing key-value pairs; these can override the defaults.

Templates can be used as a convenient mechanism for loading and storing structures in files. The write-table, save-table, or tablist functions can be used to save a table. A template table can be read in with temread or temload, and multiple tables can be read in with temloadall. These template functions have a couple advantages over using the table load functions: if the saved tables are missing fields, the defaults are filled in, and if the saved tables have extra fields, they are dropped. This provides a simple mechanism of upgrading data formats.

The following code defines a circle template with x, y, and radius fields. A couple circles are defined and written to a file. A newcircle template is defined that extends the circle template by adding a color field. The circles are read in using the new template, and pick up the new color field.

arc> (deftem circle x 0 y 0 radius nil)
((x #<procedure>) (y #<procedure>) (radius #<procedure>))
arc> (= c1 (inst 'circle 'radius 10))
#hash((radius . 10) (y . 0) (x . 0))
arc> (= c2 (inst 'circle 'x 100 'y 100 'radius 5))
#hash((radius . 5) (y . 100) (x . 100))
arc> (w/outfile of "circles.arc" (write-table c1 of) (write-table c2 of))
nil
arc> (deftem (newcircle circle) color "blue")
((x #<procedure>) (y #<procedure>) (radius #<procedure>) (color #<procedure>))
arc> (temloadall 'newcircle "circles.arc")
(#hash((radius . 10) (color . "blue") (y . 0) (x . 0)) #hash((radius . 5) (color . "blue") (y . 100) (x . 100)))

While the template names and keys can be anything usable as a table index, including strings or numbers, it is customary to use symbols.

Note that the parameters to the different template operations are unexpectedly different. deftem and addtem are macros, so any symbols should not be quoted. However, the other operations are procedures, so symbols need to be quoted. deftem, addtem, and inst take each key and value as separate parameters, but templatize and the file operations based on it take the keys and values in a list of pairs. inst allows new keys that weren't present in the template to be used, while templatize does not.

Template operations

deftem template-name(s) key default-value [key default-value] ...
Creates a template. The template-name can be any table key, but typically a symbol. The template name can also be a list of template names, where the first name is the new template, and it inherits key/value pairs from the following template names. If a default-value is nil, then no default value will be used for that key, but the key is permitted in templatize and related functions.
>(deftem tem1 a "def1" b "def2")
((a #<procedure: gs2218>) (b #<procedure: gs2218>))
>(deftem (tem2 tem1) b "def3" c "def4")
((a #<procedure: gs2218>) (b #<procedure: gs2218>) (b #<procedure: gs2222>) (c #<procedure: gs2222>))
addtem template-name [key value ...]
Modifies the specified template by adding (or updating) the keys and values.
inst template-name [key value ...]
Instantiates a template. A new table is created from the key-value pairs. The table contains the default values from the template, unless they are overridden in the key-value arguments.
>(inst 'tem1 'b "newval" 'd 42)
#hash((b . "newval") (d . 42) (a . "def1"))
templatize template-name ([(key value) ...])
Instantiates a template. The key-value pairs are given as a list of two-element lists. Any keys not defined in the template are ignored.
>(templatize 'tem1 '((b "newval") (d 42)))
#hash((b . "newval") (a . "def1"))
temread template-name [input-port]
Instantiates a template from input. Reads a list from input-port or stdin and applies templatize.
>(w/instring s "((b newval d 42))" (temread 'tem1 s))
#hash((b . newval) (a . "def1"))
temload template-name filename
Instantiates a template from a file. Applies templatize to the given file.
>(temload 'tem "foo.txt")
#hash((a . "value1") (b . "newval"))
temloadall template-name file
Instantiates a template multiple times from a file, which contains multiple lists of key-value lists. Returns a list of tables.
>(temloadall 'tem "foo2.txt")
(#hash((a . "value1") (b . "newval"))
 #hash((a . "value2") (b . "newval")))
templates*
Global variable holding all templates.

Copyright 2008 Ken Shirriff.