weeks@hpdtczb.HP.COM (Greg Weeks) (05/30/91)
To illustrate a point about C programming style, here is a bit of the documentation for a typical XWindows function: XRaiseWindow (display, window) Display *display; Window window; There is an oddity here. A `display' is a pointer to a `Display', while a `window' is just a `Window'. Most of you reading this understand why this is so. `Window' is some integer type, but `Display' is a structure type; and we are all familiar with the need to use pointers to structures. Still, the code looks odd. Is this oddness necessary? Could the style be improved? At what cost? I believe that the style could be significantly improved with only minor disadvantages. The rest of this note explains how and why. TWO WAYS THAT DATA TYPES REPRESENT REAL-LIFE OBJECTS Some real-life objects are visualized in the computer as patterns of bits. For example, the integer 3 is visualized as 0...011. Other real-life objects are visualized as blocks of memory that hold varying patterns of bits. For example, my bank account, crudely modelled as holding my current balance measured in pennies, may be visualized as a block of memory holding an `int' value. As my balance changes, the value held in the block of memory changes, but the block of memory itself stays put. There is no agreed upon term for a block of memory that holds data. K&R use the term "object". Others use the term "variable". In this note, "variable" will be used to denote a block of memory that holds data. So, while the amount of money in my bank account may be represented by an `int' value, the bank account itself is represented by an `int' variable. Similarly, while the current state of a display is represented in XWindows by a structure value, the display itself is represented by a structure variable. What then is the type whose _values_ represent displays? We're looking for a type whose values represent variables. The obvious answer is pointers. This representation is not perfect -- after all, pointers and variables are different -- but it is the best we can do. So, the type whose values best represent displays is a pointer type. STRUCTURE VS POINTER So, there are two sides to the issue "Is an XWindows display a structure or a pointer?" Both sides are correct, but they tug in opposite directions. Side 1: The type whose variables best represent real-life displays is a structure type. Side 2: The type whose values best represent real-life displays is a pointer type. A symptom of this split is our problem with the declaration: Display *display; The type name and the variable name are on different sides of the issue. The name `Display' for a structure type is on Side 1. The name `display' for a pointer variable is on Side 2. A pure Side 1 declaration would rename the variable, eg: Display *displayPtr; A pure Side 2 declaration would have the name `Display' refer to a pointer type: Display display; /* HERE, `Display' IS A POINTER TYPE */ TAKING SIDES Now for value judgments. The both-sides approach of `Display *display;' is gross. Either pure Side 1 or pure Side 2 would be preferable. I'm on Side 2, for various reasons. When discussing which data types represent real-life objects, it is much tidier to have only one way to represent things -- with values. The "with variables" way makes no sense in Lisp, CLU, or Smalltalk, and I hope that it isn't much used in Pascal. Side 2 code looks nicer than Side 1 code. Side 2 code better reflects the relationships found among real-life objects. And it has fewer *'s. The pointer type is used more than the structure type. The structure type is useful only for allocating the variables that are pointed to. Side 1 code precludes data abstraction. In contrast, Side 2 code would allow displays to be implemented as indexes into an array of preallocated structures (similar to XWindows window-ids or to Unix file-descriptors). A POINT FOR SIDE 1 As noted above, the structure type is useful only for allocating the variables that are pointed to. If the allocation is in the heap, it is natural to write a function that allocates the variable and returns the pointer to it. Users of the function need never be exposed to the structure type. In Lisp, Pascal, CLU, and Smalltalk, allocation of variables that are pointed to _must_ occur in the heap. So the structure type may be hidden at no cost. But in C, it is possible, for example, to allocate a `Display' structure variable in the stack or in the data area; the address of the variable may then be passed to functions that expect a pointer. This practice is to some degree more convenient and more efficient than heap allocation. [It also violates data abstraction.] Allocating a stack (or data area) variable and passing its address to functions that expect a pointer is a practice that makes perfect sense viewed from Side 1. But it is a bit kludgy viewed from Side 2. Oh well.
weeks@hpdtczb.HP.COM (Greg Weeks) (05/30/91)
As the writer of the basenote, I think I'd better say what it was for. Mostly, I'd like to hear from people who agree. No one is likely to be swayed by the arguments themselves -- how often does that happen in notes groups? But I hope people who agree already will be able recognize their opinions in the basenote which, in summary, says this: A mutable real-life object has a fixed identity in addition to a variable state. The state may be represented with a structure, but the object itself should be represented with a pointer. To those who agree: lets commiserate.