Roger Firth's IF pages

Home

InFancy -- using Inform objects

Email
Back up

Inform is an object-oriented language, meaning that you create your game by defining a whole series of self-contained objects. Try not to think too deeply about what this means -- it turns out to be a natural and straightforward way of defining a world in which your player can roam through 'rooms' and interact with 'things'. Once you've got over the hurdle of creating your first handful of objects, you'll quickly become comfortable with the concept (though admittedly the details take longer to master). Trust me: it's worth persisting. To start with, we'll explain the organisation of an object.

"Object" directive

The basic definition of an Inform object begins with the compile-time directive Object and ends with a semicolon (;). (On a later page we'll see that an object definition can also begin with the name of an object class, but for now the Object directive will do nicely.) As with all directives, it's conventional to capitalise the first letter of Object; this helps us to remember that directives control what happens during compilation, whereas statements (which we don't capitalise) control what happens when the game runs.

 
Object  ...  ;

The content of an object definition -- what goes between the Object and the ; -- can vary from trivially simple to extremely complex, so we'll creep up on it bit by bit. The first useful realisation is that we can divide the definition into two parts: the header (its first line), and the body (all the remaining lines).

 
Object  ...    ! this line is the object's header
        ...    !
        ...    ! and these remaining lines are its body
        ;      !

(Strictly, the header material isn't constrained to a single line, but in practice it virtually always is.) The header defines two things: the object's name(s), and its relationship (if any) to a parent object. First we'll talk about the pair of names, internal and external, which an object may possess.

Object names

Compare and contrast:

The internal name (iname) ...

Whereas the external name (xname) ...

is optional

is optional

is used at compile-time when one object needs to refer to another object

is used at run-time to tell the player where he is and what he can see

cannot be changed at run-time (obviously)

can be changed at run-time, using the short_name property (and indeed is also known as the short name)

is not normally visible to the player (but see below)

can be output using print (name) iname

can be up to 32 characters long, comprising letters, digits and underscores, where uppercase and lowercase letters are equivalent, and the first character cannot be a digit

can be up to 256 characters long, with few restrictions, and must be enclosed in quotes "..."

must be unique within the program

need not be unique within the program

Here's the syntax:

 
Object  iname "xname"
        ... ;

If the game needs to mention an object which doesn't have an xname, it uses the iname in parentheses (...) or, if the object doesn't have an iname either, the object's internal number in parentheses. This looks awful -- and can happen unexpectedly even when you thought the object's name would never appear -- so it's good practice to give every object a sensible external name. And, since you can't refer within the program to an object which doesn't have an iname, you might as well consistently assign those as well. Here's a typical example:

 
Object  kitchen_table "table"
        ... ;

Object relationships

object tree

In Inform, objects can be related one to another such that any given object has at most one parent (superior) object, and any number of child (subordinate) objects. This type of relationship model is commonly represented as a tree structure, as in this example:

One of the advantages of this structure is that moving an object within the tree -- changing its parent, if you like -- automatically moves any children of that object. This reflects natural behaviour; if for example the player TAKEs the bottle (so that he, rather than the table, becomes its parent) the label and the cork travel right along too.

While these parent-child relationships change frequently during the course of a game, they need to be established in a known pattern at the game's inception. While this could be done dynamically with lots of move ... to ... ; statements in the game's Initialise() routine, it's much more efficient to set things up statically at compile-time. Remember, too, that a parent isn't essential: unlike the real world, an Inform object can start out as an orphan, acquiring and losing parents throughout its life.

Relationships are defined in the object headers. There are two possible syntaxes:

 
Object  iname "xname" parent_iname
        ... ;


Object  set_of_arrows iname "xname"
        ... ;

The first syntax is easier to explain, so we'll cover it first. Immediately after the object's xname, you can supply the iname of the object's parent. Here's our example tree using this syntax:

 
Object  kitchen "Kitchen"
        ... ;

Object  kitchen_table "table" kitchen
        ... ;

Object  bottle "bottle" kitchen_table
        ... ;

Object  label "label" bottle
        ... ;

Object  cork "cork" bottle
        ... ;

Object  glass "glass tumbler" kitchen_table
        ... ;

The kitchen object has no parent. This is one of the necessary conditions for it being a 'room'; the other is that it is possible during the game for the player to move there, thus becoming a child of the room object. The kitchen_table specifies that its parent is the kitchen, while the bottle and the glass define the kitchen_table as their parents, and so on. The essential point is: each child object specifies the iname of an object which is to be its initial parent; that parent object must already have been defined at some previous location in the program.

The alternative syntax also demands that a object's parent has already been defined, but is more reliant on precise physical ordering. Here's the same tree:

 
Object  kitchen "Kitchen"
        ... ;

Object  -> kitchen_table "table"
        ... ;

Object  -> -> bottle "bottle"
        ... ;

Object  -> -> -> label "label"
        ... ;

Object  -> -> -> cork "cork"
        ... ;

Object  -> -> glass "glass tumbler"
        ... ;

The definition of the kitchen is unchanged. This time, though, the kitchen_table doesn't explicitly mention the kitchen as its parent. Instead, it includes a single arrow -> immediately before its iname: read one arrow as saying "I'm a child of the nearest previous object without an arrow". Next, we find the bottle with two arrows -> ->, which reads as "I'm a child of the nearest previous object with a single arrow". You won't now be surprised to learn that the label's three arrows make it a child of the two-arrow bottle; the cork also has three arrows, and so it too is a child of the bottle. Finally, the glass has only two arrows, making it a child of the nearest previous single-arrow object -- the kitchen_table.

Which syntax you use is a matter for personal preference; they both achieve exactly the same results. And in fact, you might think that mixing the two formats would be a good compromise? Well it might be... as long as you maintain a consistent approach for each top-level (parentless) object. Consider this example:

 
Object  kitchen "Kitchen"
        ... ;

Object  kitchen_table "table" kitchen
        ... ;

Object  bottle "bottle" kitchen_table
        ... ;

Object  -> label "label"
        ... ;

Object  -> cork "cork"
        ... ;

Object  glass "glass tumbler" kitchen_table
        ... ;

Does it give the same results as the previous versions? Surprisingly, no: the label and the cork end up as children of the kitchen rather than the bottle. Seems that the compiler isn't counting literal sequences of ->, but instead is going by actual depth of object nesting. To achieve the desired structure, you've got to change those -> back into -> -> ->, which rather defeats the object. Bummer, I reckon.


That's covered the object header -- the name and relationship stuff. Next, we'll look at the general organisation of the rest of the object -- its body.