This file is part of the TADS Author's Manual.
Copyright © 1987, 1996 by
Michael J. Roberts. All rights reserved.
The manual was converted to HTML by N. K. Guy, tela design.
Chapter Two
Somewhere around 1985, the software marketing community discovered the term "object oriented," and latched onto the phrase with a devotion that even "hypertext" and "multi-media" have yet to approach. With so many marketers using the term, and so few knowing what it means, "object oriented" has come to mean almost anything, and hence nothing.
Despite the confusion, the term really does have a meaning. This section will attempt to clarify what object-oriented programming is and how it applies to TADS. This chapter will also explain why an object-oriented language is desirable when writing adventures.
This section is not "required reading" in learning TADS, but it may help you understand some of the general ideas that influenced the design of the system. You may prefer to skip this chapter the first time you read this Author's Manual, and come back to it after you have a general understanding of the language.
TADS is an object-oriented programming language. Object-oriented languages are similar in many ways to "procedural" languages such as C and Pascal, but approach problem-solving from a different perspective. Because of the shift in viewpoint, object-oriented programming is effective in many different kinds of applications, but it is particularly applicable to simulations. A text adventure is fundamentally a simulation.
What is this "new perspective" of object-oriented programming? Basically, it is the view that one takes of data. In a traditional language, you write a series of procedural steps that are applied to a collection of data; code and data are firmly separated. In object-oriented programming, on the other hand, you partition a problem into a set of entities, called objects; each object contains both the data and the code that describes its state and behavior. In a simulation, an object in the program usually corresponds directly to an object being modelled.
Consider a simulation of a physics problem involving bouncing balls of various kinds. In a traditional language, we would define a set of data for each ball (such as its position, mass, and velocity); we would give each ball some sort of identification (perhaps a number, giving an array index) that would let us tell the balls apart. Finally, a subroutine named bounce would be written; the subroutine would take a ball number as its parameter, and would apply the appropriate changes to the ball's data.
In contrast, an object-oriented version of the program would model each ball with an object. Not only would the data about a ball be contained in the object representing the ball, but the code needed to describe its behavior under various interactions would be contained in the object as well. So, each ball would have its own bounce method (the object-oriented word for a subroutine that is associated with a particular object or group of objects). Rather than calling the bounce subroutine with an argument specifying ball 3, you would send ball 3 a message telling it to bounce ("send a message" is the object-oriented term for calling a method).
This may sound like a lot of coding, writing the same subroutine for each ball. Fortunately, object-oriented languages have a feature that avoids this type of duplication. This feature is inheritance. An object can be defined as belonging to a particular class, and it will inherit all of the code and data defined for the class. Of course, it can still define code and data itself, which can add to or modify the attributes it inherits. When an object defines code or data that is already defined by its class, the definitions the object makes override what it inherits from its class.
The utility of inheritance and overriding is that it becomes very simple to represent general and special cases. For example, if you had twenty identical balls, but a twenty-first ball with special behavior when bouncing (but apart from bouncing is the same as all the other balls), you'd first define a ball class, and define all twenty-one balls as belonging to this class. The twenty-first ball, though, would override the bounce method with its own special version. In a traditional language, on the other hand, the bounce subroutine would need a special test to see if the odd ball was bouncing and act accordingly.
This may seem like six of one and half a dozen of the other, but it has a big advantage: it isolates the special case code with the special case object. Just as block-structured languages allow code to be modularized, object-oriented languages allow entire objects - both their state and their behavior - to be modularized. Most people find that this makes writing a program much easier, because they only need to think about a special case in one place, rather than tracking down all the subroutines that need to be modified. It is especially helpful when debugging and maintaining a program, because everything pertaining to an object is kept in one place.
Note that since a class can itself be a member of another class, this type of specialization can be extended indefinitely. For example, you could define the classes rubberBall and billiardBall, each inheriting characteristics from the more general class ball and defining some of their own. Now you could define ten objects of each class, and these objects could themselves define characteristics overriding their two parent classes.
Object-oriented languages are quite useful for writing adventure games. When a player types a command in a TADS game, the system sends certain messages to the object or objects involved. In this way, it's easy to define classes of objects that behave in particular ways in response to player commands. For example, objects that the player can't pick up (such as phone booths and anvils) respond with a simple "You can't have that" to a "take" command, whereas objects that can be carried will move themselves into the player's inventory list. The basic adventure file adv.t defines a large number of basic classes, but the real power of TADS is the ability to add classes of your own.
Users of other languages that have object-oriented features, such as C++ or Smalltalk, will find that TADS has a slightly different approach to object-oriented programming. In particular, TADS makes much less of a distinction between classes and objects than other languages.
In C++ and Smalltalk, a class is a template that specifies the data types stored by members of the class, but only an object actually stores values for the data. (This is analogous to the distinction between a structure and instances of the structure in a language such as C or Pascal: the structure defines the layout of data, but only an instance of the structure actually contains any data.) The inheritance structure pertains to the classes; an object is an instance of a particular class, so only methods and "slots" for data can be inherited - values for data items are not themselves inherited.
In TADS, there is no distinction between classes and instances of classes, in that a class is also an object. Hence, data values as well as methods can be inherited from a parent object. In TADS, the only distinction between a class and a normal object is that a class object is ignored by the player command parser.
This different approach leads to a different style of programming. A TADS program consists mostly of definitions of objects (instances of classes). All of the instances are specifically defined, with values for properties, in the game program. In contrast, a C++ or Smalltalk program usually defines mostly classes, and creates instances at run-time.
The noblest function of an object is to be contemplated.
MIGUEL DE UNAMUNO, Mist (1914)
Chapter One | Table of Contents | Chapter Three |