16. Tables

Writing with Inform

WI §16.1 Laying out tables

When printed books need to display detailed information in a systematic way, they break off from running text and print a table instead. Inform does the same. Here is a typical example:

Table 2.1 - Selected Elements
ElementSymbolAtomic numberAtomic weight
"Hydrogen""H"11
"Iron""Fe"2656
"Zinc""Zn"3065
"Uranium""U"92238

After the two titling lines, each line represents one row in the table, and entries on a line must be separated by at least one tab character. A table must occupy a single whole paragraph, with no skipped lines or missing entries.

The top line is a title, the first word of which must be the word 'Table'. We can then either give a table number (this need not actually be a number: Table C2, or some such, would be fine), or give a name, or both – as in this case. The possible titling formats are:

Table 2.3
Table of Population Statistics
Table 2.3 - Population Statistics

In the last example we could call the table either "Table 2.3" or "Table of Population Statistics".

Each column then has a name, and the contents must all be the same kind of value. In the elements table the "Symbol" column contains only text, for instance, and the "Atomic weight" column contains only numbers. Any kinds of value will do, so long as all the entries in the column are mutually compatible. (For instance, mixing rooms and things in a single column would be fine, as these can be reconciled, but mixing numbers and rooms would not.)

WI §16.2 Looking up entries

The simplest way to access the information inside tables is to ask explicitly for it, specifying the row number, the column name and what table is to be consulted. So, given our example table

Table 2.1 - Selected Elements
ElementSymbolAtomic numberAtomic weight
"Hydrogen""H"11
"Iron""Fe"2656
"Zinc""Zn"3065
"Uranium""U"92238

we can write the following description:

symbol in row 3 of the Table of Selected Elements

to produce the value "Zn". Or the following will run off some chemical data:

repeat with N running from 1 to the number of rows in the Table of Selected Elements:
   say "The atomic weight of [element in row N of the Table of Selected Elements] is [atomic weight in row N of the Table of Selected Elements]."

The result of which will be:

The atomic weight of Hydrogen is 1.
The atomic weight of Iron is 56.
The atomic weight of Zinc is 65.
The atomic weight of Uranium is 238.

Note that the first row in a table is row number 1, and that the last can be found with the phrase:

number of rows in/from (table name)number

This phrase produces the number of rows (including any blank rows) in the given table. Example:

number of rows in the Table of Selected Elements

WI §16.3 Corresponding entries

Continuing our example of the elements:

Table 2.1 - Selected Elements
ElementSymbolAtomic numberAtomic weight
"Hydrogen""H"11
"Iron""Fe"2656
"Zinc""Zn"3065
"Uranium""U"92238

If we want to know the atomic number of Uranium, say, it seems artificial to have to talk about the particular row number where the information happens to be. So we are also allowed to cross-reference, like so:

the atomic number corresponding to a symbol of "Fe" in the Table of Selected Elements

This results in 26, and similarly

the symbol corresponding to an atomic number of 26 in the Table of Selected Elements

results in "Fe". But we have to be careful:

the element corresponding to an atomic number of 27 in the Table of Selected Elements

This is not allowed (it produces an error at run-time), because there is no row with atomic number 27 in this rather limited table. We can check this in advance with the condition:

if there is an element corresponding to an atomic number of 27 in the Table of Selected Elements ...

Or more simply:

if there is an atomic number of 27 in the Table of Selected Elements ...

The condition "if there is…" can be used with any reference to a table entry: for instance, "if there is a symbol in row 5 of the Table of Selected Elements" would be false, because there are only four rows.

Example

271.
Dubai ★★★
An elevator which connects any of 27 floors in a luxury hotel.

WI §16.4 Changing entries

Here is another rather definitive, immutable-looking table:

Table 4 - Recent Monarchs
NameAccessionFamily
"Anne"1702Stuart
"George I"1714Hanover
"George II"1720Hanover
"George III"1760Hanover
"George IV"1820Hanover
"William IV"1830Hanover
"Victoria"1837Hanover
"Edward VII"1901Saxe-Coburg-Gotha
"George V"1910Windsor
"Edward VIII"1936Windsor
"George VI"1936Windsor
"Elizabeth II"1952Windsor

But table entries can be changed as freely as variables: that is, any value can be entered so long as it has the right kind. We cannot put a dynasty into the "Name" column, or text in the "Accession" column. The phrase needed is "now … is …", just as it is for properties or variables:

Dynasty is a kind of value. The dynasties are Stuart, Hanover, Saxe-Coburg-Gotha and Windsor.
The Table Office is a room. The Succession is in the Table Office. "The Succession, a ponderous list of English monarchs, takes pride of place."
Instead of examining the Succession:
   say "The Succession List runs as follows...";
   repeat with N running from 1 to the number of rows in the Table of Recent Monarchs:
      say "[accession in row N of Table 4]: [name in row N of Table 4] ([family in row N of Table 4])."
Instead of attacking the Succession:
   now the family corresponding to an accession of 1720 in the Table of Recent Monarchs is Stuart;
   now the name in row 4 of the Table of Recent Monarchs is "Graham I";
   now the name in row 5 of the Table of Recent Monarchs is "Trixibelle IV";
   say "You deface the English succession, making suitable amendments with a quill pen. Considering it is supposed to be mightier than the sword the effect is a little disappointing."
Test me with "examine succession / attack it / examine it".

Once we start changing tables, it sometimes becomes useful to check what they contain.

showme the contents of (table name)

This phrase prints a crude but sometimes useful display on screen of the current contents of the named table. It's intended for authors to see when testing, not for players of the finished version to see.

say "[current table row]"

This text substitution produces a crude but sometimes useful listing of the entries in the currently chosen table row.

say "[row (number) in/from table (table name)]"

This text substitution produces a crude but sometimes useful listing of the entries in the specified row.

say "[(column name) in/from table (table name)]"

This text substitution produces a crude but sometimes useful listing of the entries in the specified column.

WI §16.5 Choosing rows

The following would be one way to print out a list of recent Kings and Queens:

To list the succession:
say "The Succession List runs as follows...";
repeat with N running from 1 to the number of rows in the Table of Recent Monarchs:
   say "[accession in row N of the Table of Recent Monarchs]: [name in row N of the Table of Recent Monarchs] ([family in row N of the Table of Recent Monarchs])."

This works, but is repetitive. We often want to work on a single row for a while, either to change things or think about the contents, and it is tiresome to keep specifying the row over and over again. The following shorthand provides some relief:

choose a/the/-- row (number) in/from (table name)

This phrase selects the row with the given number. Row numbers in a table start from 1, so

choose row 1 from the Table of Recent Monarchs

selects the top row.

That allows us to improve the loop:

To list the succession:
   say "The Succession List runs as follows...";
   repeat with N running from 1 to the number of rows in the Table of Recent Monarchs:
      choose row N in the Table of Recent Monarchs;
      say "[accession entry]: [name entry] ([family entry]).";

Actually, as we'll see in the next section, this kind of loop is needed so often that there's a shorthand wording for it.

Note that since "accession" is a column name, "accession entry" means the entry in that column of the currently chosen row. This notation can only be used if a "choose" has certainly already happened, and it is a good idea to make that choice somewhere close by in the source code (and certainly in the same rule or phrase definition) for the sake of avoiding errors. We can also choose rows by specifying something about them, like so:

choose a/the/-- row with (table column) of (value) in/from (table name)

This phrase selects the first row, working down from the top of the given table, in which the given column has the given value. Example:

choose row with a name of "Victoria" in the Table of Recent Monarchs;

A run-time problem message is produced if the value isn't found anywhere in that column.

Sometimes it will happen that a column's name clashes with the name of something else: for instance, if we call a column "apples" but we also have a kind called "apple", so that the word "apples" could mean either some fruit or the column. Inform will generally prefer the former meaning as more likely. In case of such trouble, we can simply refer to "the apples column" rather than just "the apples": for instance, "choose row with an apples column of…" rather than "choose row with an apples of…"

We can also choose a row quite at random:

choose a/the/-- random row in/from (table name)

This phrase makes a uniformly random choice of non-blank rows in the given table. Note that although a table always has at least one row, it can't be guaranteed that it always has a non-blank row, so it's possible for this to fail: if it does, a real-time problem message is thrown.

WI §16.6 Repeating through tables

We very often want to run through a table doing something to, or with, each row in turn, so a special loop is provided for this. Rather than having to write all this out:

To list the succession:
   say "The Succession List runs as follows...";
   repeat with N running from 1 to the number of rows in the Table of Recent Monarchs:
      choose row N in the Table of Recent Monarchs;
      say "[accession entry]: [name entry] ([family entry])."

We can simply use this instead:

repeat through (table name):

This phrase causes the block of phrases following it to be repeated once for each row in the given table, choosing each row in turn, from top to bottom. Blank rows are skipped. Example:

To list the succession:
   say "The Succession List runs as follows...";
   repeat through the Table of Recent Monarchs:
      say "[accession entry]: [name entry] ([family entry])."

Note that there is no loop variable here, unlike in other forms of "repeat", because it's the choice of row which keeps track of how far we have got.

We can alternatively go backwards:

repeat through (table name) in reverse order:

This phrase causes the block of phrases following it to be repeated once for each row in the given table, choosing each row in turn, from bottom to top. Blank rows are skipped.

More often we want a sequence which is neither forwards nor backwards, but which depends on the actual values in the table.

repeat through (table name) in (table column) order:

This phrase causes the block of phrases following it to be repeated once for each row in the given table, choosing each row in turn, in order of the values in the given column. Blank rows are skipped. Example:

repeat through the Table of Recent Monarchs in name order: ...
repeat through the Table of Recent Monarchs in accession order: ...

work through the same table in rather different orders. The sequence is lower to higher (small numbers to high numbers, A to Z, and so on); insert "reverse" after "in" to reverse this.

repeat through (table name) in reverse (table column) order:

This phrase causes the block of phrases following it to be repeated once for each row in the given table, choosing each row in turn, in order of the values in the given column. Blank rows are skipped. Example:

repeat through the Table of Recent Monarchs in reverse name order: ...
repeat through the Table of Recent Monarchs in reverse accession order: ...

work through the same table in rather different orders. The sequence is higher to lower (high numbers to small numbers, Z to A, and so on); delete the "reverse" after "in" to reverse this.

In a loop like this, the data is not searched very efficiently, which is fine for modest-sized tables like the examples in this chapter, but might be a problem for much larger tables: see the later section on sorting.

These definitions mentioned blankness several times, and that's the topic to cover in the next section.

See Also

Sorting for reordering a table to put it into increasing or decreasing order of the entries in any column.

Example

272.
A cell window through which the player can see people who were in Port Royal in the current year of game-time.

WI §16.7 Blank entries

We are allowed to leave certain entries blank (perhaps to be filled in later, perhaps not) by writing "--" instead of the relevant value:

Table 2.1 - Selected Elements
ElementSymbolAtomic numberAtomic weight
"Hydrogen""H"11
"Iron""Fe"--56
"Zinc"--3065
"Uranium""U"92238

In effect, blank entries don't exist. "--" is not a value, but only a hole where a value might be. It can be useful to check for this:

if there is (a table entry):

This condition is true if the entry referred to exists, that is, that is, the space for it in the table is not blank. Examples:

if there is a symbol corresponding to an atomic number of 30 in the Table of Selected Elements ...
if there is an atomic number in row 2 of the Table of Selected Elements ...
if there is no (a table entry):

This condition is true if the entry referred to does not exist, that is, the space for it in the table is blank. Examples:

if there is no symbol corresponding to an atomic number of 30 in the Table of Selected Elements ...
if there is no atomic number in row 2 of the Table of Selected Elements ...

WI §16.8 Blank columns

An entire column of blank entries "--" is problematic:

Table 2 - Selected Elements
ElementSymbolAtomic numberAtomic weight
"Hydrogen""H"1--
"Iron""Fe"26--
"Zinc""Zn"30--
"Uranium""U"92--

Inform is unable to work out what kind of value should go into the "atomic weight" column here, since it has no examples to guess from. We can get around this by writing in the name of a kind of value:

Table 2 - Selected Elements
ElementSymbolAtomic numberAtomic weight
"Hydrogen""H"1a number
"Iron""Fe"26--
"Zinc""Zn"30--
"Uranium""U"92--

That top entry in the "atomic weight" column is also blank, but now Inform knows that anything put into the column in future will be a number.

If there are many rows, and perhaps several blank columns, it would become very tedious to have to keep typing out "--". So this is optional at the end of a row: it remains compulsory for a blank value appearing in between two values which aren't blank. This is the general idea:

Table 2 - Selected Elements
ElementSymbolAtomic numberDensitySpecific gravity
"Hydrogen""H"1a numbera number
"Iron""Fe"26  
"Zinc""Zn"30  
"Uranium""U"92  

WI §16.9 Blank rows

There is no difficulty about entirely blank rows: or rather, the only difficulty is once again that they are boring to type out. We can avoid the necessity by appending "with … blank rows" at the foot of the table:

Table 2 - Selected Elements
ElementSymbolAtomic numberAtomic weight
"Hydrogen""H"1a number
"Iron""Fe"26--
"Zinc""Zn"30--
"Uranium""U"92--
with 3 blank rows

(These words cannot be placed in between rows, but only at the bottom.) And indeed the table can start out completely empty:

Table 3 - Undiscovered Periodic Table
Element (text)Symbol (text)Atomic number (a number)Atomic weight (a number)
with 92 blank rows

Blank rows are useful because they enable us to add new data to a table. In effect, they are invisible when not used. A repeat loop like

repeat through Table 3:
   ...

automatically skips blank rows, so it would initially do nothing at all. Similarly, choosing a "random" row will never choose a blank one.

A convenient way to test if a table contains non-blank rows is to use the built-in adjectives "empty" and "non-empty". So:

if the Undiscovered Periodic Table is empty, ...

tests whether all of its rows are blank; if even one cell contains a value then the table is "non-empty".

Example

A sound recording device that records the noises made by player and non-player actions, then plays them back on demand.

WI §16.10 Adding and removing rows

Writing in new rows is simple, once we can find space for them:

choose a/the/-- blank row in/from (table name)

This phrase chooses a row in the given table which is currently blank under every column. A run-time problem message is issued if no rows are blank. Example:

choose a blank row in Table 3;
now element entry is "Fluorine";
now symbol entry is "F";
now atomic number entry is 9;
now atomic weight entry is 19;

To avoid problem messages, it can be important to worry about free space. To that end we can not only find the number of rows (as we have already seen) but also the number currently blank and not blank:

number of blank rows in/from (table name)number

This phrase produces the number of rows in the given table which are entirely blank (that is, blank under every column).

number of filled rows in/from (table name)number

This phrase produces the number of rows in the given table which are not entirely blank (that is, at least one column has a value in this row).

"Filled" here really means "non-blank": a row can be filled in this sense even if only one of its values exists. Since every row is either blank or filled, it must be true that:

the number of blank rows in Table 3
the number of filled rows in Table 3

add up to "the number of rows in Table 3".

We've seen that blank entries can be filled with values using "now":

now symbol entry is "F";

But the same method can't be used to put blanks back, since a blank is not a value. Instead:

blank out (a table entry)

This phrase replaces the entry referred to with a blank, erasing any value previously stored there. Example:

choose row 1 in the Table of Fish Habitats;
blank out the salinity entry;

These more destructive phrases need a steady hand:

blank out the whole row

This phrase replaces the currently chosen row with blanks, erasing any value previously stored under any of the columns. Example:

choose row 1 in the Table of Fish Habitats;
blank out the whole row;
blank out the whole (table column) column in (table)

This phrase replaces the currently chosen column with blanks, erasing any value previously stored in any of the rows. Example:

blank out the whole salinity column in the Table of Fish Habitats;
blank out the whole of (table)

This phrase replaces every row of the currently chosen table with blanks, erasing any value previously stored anywhere in it. Example:

blank out the whole of the Table of Fish Habitats;

This is only really useful when a Table is being used to hold working space for some calculation or other.

Example

274.
Odyssey ★★
A person who follows a path predetermined and stored in a table, and who can be delayed if the player tries to interact with her.

WI §16.11 Sorting

The three ways to sort a table correspond loosely to the three different orders in which tables can be repeated through. First:

sort (table name) in random order

This phrase rearranges the rows of the given table so that the non-blank rows occur at the top, in a uniformly random order, and any blank rows at the bottom. Example:

sort the Table of Recent Monarchs in random order;

Secondly:

sort (table name) in (table column) order

This phrase rearranges the rows of the given table so that the non-blank rows occur at the top, so that the given column has ascending order, and any blank rows at the bottom. Example:

sort the Table of Recent Monarchs in accession order;

Ascending order means 1 up to 10, say, or A up to Z, with blank values coming last.

sort (table name) in reverse (table column) order

This phrase rearranges the rows of the given table so that the non-blank rows occur at the top, so that the given column has descending order, and any blank rows at the bottom. Example:

sort the Table of Recent Monarchs in reverse name order;

Descending order means 10 down to 1, say, or Z down to A, with blank values coming last.

How sorting is done depends on the contents of the column being sorted on. If it holds numbers then numerical order is used, with 2 coming before 7, and so on. (And similarly for real numbers, though the existence of infinities makes this more interesting.) If times are sorted then they are sorted from midnight to midnight, following the "is greater than" relation, not with 4 AM as the zero point, as with "is after".

If text is sorted then alphabetical order is used, though this doesn't always come out the way you might expect, because upper case and lower case letters are treated as different: A-Z come before a-z, and accented letters such as é come after the regular alphabet. (What's happening here is that Inform is sorting on raw character values, not performing the full Unicode collation algorithm, which would be too slow at run-time.)

Note that blank values will always be placed below non-blank ones, and entirely blank rows last of all. This is true even if we use "reverse".

The method of sorting is "stable", that is, if two rows have the same value then they will stay the same way round in the sorted table, rather than being swapped over. For example, if we sort this into reverse index order:

IndexComment
1"Originally row 1"
2"Originally row 2"
2"Originally row 3"
3"Originally row 4"

then we get

IndexComment
3"Originally row 4"
2"Originally row 2"
2"Originally row 3"
1"Originally row 1"

As a result note that repeating through this sorted table goes through the original rows in order 4, 2, 3, 1; whereas repeating through the original table in reverse order goes through in order 4, 3, 2, 1. (This is all to explain the word "loosely" in the opening sentence of this section.)

Example

275.
A deck of cards which can be shuffled and dealt from.

WI §16.12 Listed in...

Tables are especially useful for combining a run of basically similar rules in a simple and concise way. The "listed in" condition, as in

if the newfound object is an item listed in the Table of Treasures...

looks through a given table (here "table of treasures"), in a given column ("item"), to see if a given value is present ("the newfound object"). If this is successful, the row where it was found is automatically chosen; but if not, note that any existing row selection will be lost, so make use of the row only if the test succeeds.

We can similarly use "… listed in …" in a description used when specifying an action. Thus:

After taking an item listed in the Table of Treasures:
   if there is no time entry:
      now the time entry is the time of day;
      increase the score by the value entry;
   say "Taken!"

This assumes a table in the following shape:

Table of Treasures
ItemValueTime
brooch5a time
tiara8--
coronet10--

In effect the table has allowed us to combine three very similar rules into one. The time column records the first time at which the item has been picked up, which starts out blank since at the start of play it has never been picked up. This enables us to award the appropriate number of points on the first occasion only.

Example

276.
Noisy Cricket ★★★
Implementing liquids that can be mixed, and the components automatically recognized as matching one recipe or another.

WI §16.13 Topic columns

When double-quoted matter appears in a column of a table, Inform will normally treat that as text for printing out. The exception is when the column is called "topic", where it is treated as text for comparing against what the player has typed. There is really only one operation allowed with topic columns, the "…listed in…" construction, but fortunately it is the one most often needed.

Let us suppose that the Sybil has a penchant for telling passers-by which is the Greek muse for what. We might write:

After asking the Sybil about a topic listed in the Table of Sybil's Replies, say "The Sybil declaims for a while, the gist being that the muse in question looks after [muse entry]."

We can then provide a simple table giving her responses:

Table of Sybil's Replies
TopicMuse
"calliope""epic poetry"
"clio""history"
"erato""love poetry"
"euterpe""music"
"melpomene""tragedy"
"polyhymnia""sacred poetry"
"terpsichore""dancing"
"thalia""comedy"
"urania""astronomy"
"monica""tidiness"
"phoebe""massage"
"rachel""oval hair-cuts"

Topics can use the full range of abilities of the "understanding" system which Inform uses to parse text, and which will be the subject of a later chapter. For now, note that the Sybil's topics might equally include "flora/eve" (matching the single word "flora" or the single word "eve"), or something more elaborate such as:

"Bridget" or "Bridge" or "Bridget Jones"

See Also

Understand for the system Inform uses to parse text.

Examples

277.
Merlin
A REMEMBER command which accepts any text and looks up a response in a table of recollections.
An expansion on the previous idea, only this time we store information and let characters answer depending on their expertise in a given area.
279.
Allowing the player to use question words, and using that information to modify the response given by the other character.

WI §16.14 Another scoring example

To record (T - text) as achieved:
   choose row with a citation of T in the Table of Tasks Achieved;
   if there is no time entry:
      now time entry is the time of day;
      increase the score by the points entry.

The phrase above expects to see a table like this one:

Table of Tasks Achieved
PointsCitationTime
1"pride"a time
3"anger" 
2"avarice" 
4"envy" 
1"lust" 
2"gluttony" 
3"sloth" 

The middle column records the tasks to be achieved, the first column records the points on offer for each: the final column, initially blank, will store the times at which the tasks are first achieved.

Before eating, record "gluttony" as achieved.

The first time we record "gluttony" as achieved, 2 points will be awarded and the time will be logged in the Table, but on all subsequent occasions nothing will happen. So the combination of the phrase and the Table will look after a scoring system based on achieving specific goals (probably not the seven deadly sins, of course). We can, if we choose, use the same system to display a log of recent accomplishments:

repeat through the Table of Tasks Achieved in reverse time order:
   say "[time entry]: [citation entry] ([points entry])."

Example

Implementing a FULL SCORE command which lists more information than the regular SCORE command, adding times and rankings, as an extension of the example given in this chapter.

WI §16.15 Varying which table to look at

So far, we have always used fixed table names when referring to tables: for instance in source like "sort the Table of Recent Monarchs in accession order", we refer to the "Table of Recent Monarchs", a definite and explicitly named table.

With a little care, however, we are allowed to have variables which themselves hold the names of tables. This opens up the possibility of more elaborate ways of storing and interconnecting information in table form, but is probably best avoided until it becomes necessary.

For example, suppose we have two different tables with the same basic structure:

Table 1 - Nifty Opening Plays in US Scrabble
wordscore
"muzjiks"128
Table 2 - Nifty Opening Plays in UK Scrabble
wordscore
"quartzy"126
"squeezy"126

We could then record which one of these tables to use in a variable:

The lexicon is a table name that varies. The lexicon is Table 1.

Note that for this purpose, the kind of value is a special kind called "table name", not "table". (The word "table" already has too many meanings and we must be careful to avoid ambiguities here.) We could make use of this as follows, for instance:

To flip tables:
   say "You exchange dictionaries, lexically crossing the Atlantic. ";
   if the lexicon is Table 1, now the lexicon is Table 2;
   otherwise now the lexicon is Table 1;
   choose a random row in the lexicon;
   say "Did you know that according to [the lexicon], [word entry] scores [score entry]?"

which produces text such as

You exchange dictionaries, lexically crossing the Atlantic. Did you know that according to Table 1 - Nifty Opening Plays in US Scrabble, muzjiks scores 128?

Example

281.
Farewell ★★
People who respond to conversational gambits, summarize what they said before if asked again, and provide recap of conversation that is past.

WI §16.16 Defining things with tables

Suppose we need to create a collection of items which differ in their properties, but are basically part of a larger pattern. For instance, here we set up what we need to make a collection of coloured shirts:

A jersey is a kind of thing. A jersey is wearable. A jersey has a number called year established. A jersey has a text called citation. The description of a jersey is "Since [year established], the Tour de France has awarded this jersey to the [citation]."

Now we have the pattern, but making the actual shirts is tedious and repetitive:

The yellow jersey is a jersey. The year established of the yellow jersey is 1919. The citation of the yellow jersey is "race leader". The polkadot jersey...

And so on. Instead, we can use a table to abbreviate all of this:

"Tour des Maillots"
The Staging Area is a room. A jersey is a kind of thing. A jersey is wearable. Some jerseys in the Staging Area are defined by the Table of Honorary Jerseys. The description of a jersey is "Since [year established], the Tour de France has awarded this jersey to the [citation]."
Table of Honorary Jerseys
jerseyyear establishedcitation
a yellow jersey1919"race leader"
a polkadot jersey1933"King of the Mountains"
a green jersey1953"highest point scorer on sprints"
a white jersey1975"best cyclist aged 25 or less"

The first column provides names for the new things to be created. Subsequent columns provide property values. Note that we did not need to say that jerseys have a number called "year established" because Inform is able to infer this from the column heading and the presence of numbers in the column; similarly for "citation". Lastly, note that if any entry is blank (written "--") then that particular property is simply not set for that particular item.

Note that Inform reads articles such as "the" or "a" in the first column just as it would when something is created with any other sentence.

It's even possible to define kinds this way, though it's rare to need to create many kinds at once. (See the worked example "Reliques of Tolti-Aph" at the Inform website. There's no special syntax needed: rather than saying "Some jerseys are defined by…" we would say "Some kinds of jersey are defined by…")

Examples

282.
Sweeney ★★
A conversation where each topic may have multiple questions and answers associated with it, and where a given exchange can lead to new additions to the list.
Assortment of equipment defined with price and description, in a table.

WI §16.17 Defining values with tables

Just as we can define many similar things (or kinds) using a table, we can also define a whole run of new values. Again, this avoids unnatural prose like

The chemical elements are Hydrogen, Helium, Lithium, ..., and Ununquadium.

We can give these new values properties, too. For example:

Solar distance is a kind of value. 1000 AU specifies a solar distance. Planet is a kind of value. The planets are defined by the Table of Outer Planets.
Table of Outer Planets
planetsemimajor axis
Jupiter5 AU
Saturn10 AU
Uranus19 AU
Neptune30 AU
Pluto39 AU

creates five values of the kind "planet", but it also makes a property called "semimajor axis" which belongs only to these five values. Thus:

say "Pluto orbits at [semimajor axis of Pluto]."

produces "Pluto orbits at 39 AU." We can both use and change this value:

Praying is an action applying to nothing. Understand "pray" as praying.
Instead of praying:
   now the semimajor axis of Pluto is 1 AU;
   say "Your prayers are answered, and the Almighty moves Pluto in closer to the fire."

Similar properties would be made for each column of the table after the first (there can be any number of properties, including none). Because the values are created first, before the rest of the table is gone through, we can even use "planet" as one of the values of properties:

Table of Outer Planets
planetsemimajor axiscentre of government
Jupiter5 AUJupiter
Saturn10 AUSaturn
Uranus19 AUSaturn
Neptune30 AUPluto
Pluto39 AUPluto

All of this is intended to be closely parallel to defining a whole run of things, such as the coloured jerseys, using a table, but there are two important restrictions: firstly, when a kind of value is defined by table, the table must contain all of its possible values; and secondly, the column names (after the first) cannot coincide with names of any properties held by any other value (or thing, for that matter). So it is a good idea to give the columns very specific names ("centre of government") rather than vague names which might cause clashes elsewhere ("owner").

Two technical footnotes. In a table used to define a kind of value, blank entries are not left blank: they are filled in with suitable default values. For instance, if the semimajor axis column had been all "--"s except for listing Neptune at "30 AU", say, Inform would deduce that the column was meant to hold a value of kind "solar distance", and would set the solar distances for all of the other planets to be "0 AU". It does this to ensure that "solar distance of P" exists for any planet P.

The second technical note is that we must not sort such a table, because it is used during play to store the properties, and if it were to get rearranged then so would the properties be – with probably disastrous results.

WI §16.18 Table continuations

A table is an arrangement for putting information together concisely in a single place, so it might seem odd that we sometimes need to divide it up: but once in a while, we do. Suppose we have:

Table of Outer Planets
planetsemimajor axis
Jupiter5 AU
Saturn10 AU
Uranus19 AU
Neptune30 AU
Pluto39 AU

But then someone in Chile with a telescope the size of God's own teacup notices something a long, long way out, and the newspapers get terribly excited. We can write an addendum:

Table of Outer Planets (continued)
planetsemimajor axis
Orcus39 AU
Quaoar43 AU
Xena68 AU
Sedna524 AU

This may seem unnecessary – why not simply add extra rows to the original table? – but it allows us to split the table between different parts of the source text, if we want to, or to continue a table which exists only in an extension. (Thus if we were using an extension which involved the planets, and had a table like this one, we would be able to add new planets without changing the extension.)

The name for the continuation must be identical to the original. The continuation has no existence in its own right: Inform simply splices the two (or more) pieces together, exactly as if the table were all in one piece at the place where it first occurred. Thus the above creates only one table, the "Table of Outer Planets", with nine rows. Each column in the continuation must exist in the original, but not every column need be given: those omitted are filled with blank entries. The columns need not be in the same order. Both original and continuations are allowed to quote a number of blank rows: if so, the combined total is used.

At time of writing the International Astronomical Union has not yet consented to name 2003 UB313 after Xena, the Warrior Princess, but this is surely only a bureaucratic delay. (Footnote: on 24 August 2006 it was demoted to dwarf planet status, like the luckless Pluto, and on 13 September renamed Eris; though its moon's official name, Dysnomia, is an ingenious double-meaning to do with the name of Xena's actress, Lucy Lawless.)

Example

Using a menu system from an extension, but adding our own material to it for this game.

WI §16.19 Table amendments

Tables can have amendments as well as continuations. The arrangement is much the same: a supplementary table supplies new rows for the original table. But instead of adding the new rows at the end of the original, as a continuation would, an amendment replaces matching rows in the original. (So the original stays the same size.)

The amendment table must have exactly the columns of the original and in the same order. Moreover, each row in the amended table must match exactly one row in the original. For instance:

Table of Plans
momentoutcome
10 AM"takeover of Mars"
11:30 AM"canals reflooded"
11:45 AM"chocolate bar production doubled"
Table of Plans (amended)
momentoutcome
11:45 AM"volcanic cave production doubled"

creates a three-row Table of Plans, with reference to the chocolate bars struck out.

Amendment rows may be given in any order. The process of matching a row begins at the left-most column: Inform tries to see if any single row in the original table has a matching entry. If none does, a Problem is issued. If more than one do, Inform then looks at the second column, and so on. For instance:

Enthusiasm is a kind of value. The enthusiasms are pumped, wired and languid.
Table of Mental States
feelingextentconsequence
pumped1"you feel able to run for your life"
pumped2"you feel able to run for President"
wired1"you feel able to run"
languid1"you feel"
Table of Mental States (amended)
feelingextentconsequence
pumped2"you feel able to run for the Nebraska State Legislature"

Here the amendment is made to the second row of the original table. The value in the leftmost column, "pumped", matches two rows in the original, so Inform moves on to the next column, reads "2", and finds that only one row in the original still qualifies – so that is the one replaced.

For the present, at least, the columns used for matching may only contain: numbers, times, objects, action names, activities, figure names, sound names, truth states and any new kinds of value or units which have been declared.

Example

285.
Trieste ★★
Table amendment to adjust HELP commands provided for the player.