thinman@netcom.com (Lance Norskog) (04/22/91)
- 17 - ( op name=Imag type=Number ( template ID=output (type=Complex ID=input) ) ( rewrite (set (output, input1.im)) ) ) / arithmetic operators / C1 + C2 = C1.re + C2.re, C1.im + C2.im ( op name=+ type=Number ( template ID=output (type=Complex ID=input1) (type=Complex ID=input2) ) ( rewrite (set(output.re, (op name=+ (op name=Real(input1)) (op name=Real(input2)) ) )) (set(output.im, (op name=+ (op name=Imag(input1)) (op name=Imag(input2)) ) )) ) ) / C1 - C2 = C1.re - C2.re, C1.im - C2.im / elided for brevity - 18 - / C1 * C2 = (C1.re * C2.re) - (C1.im * C2.im), (C1.re * C2.im) + (C2.re * C1.im), ( op name=* type=Number ( template ID=output (type=Complex ID=input1) (type=Complex ID=input2) ) ( rewrite (set(output.re, (op name=- (op name=* (op name=Real(input1)) (op name=Real(input2)) ) (op name=* (op name=Imag(input1)) (op name=Imag(input2)) ) ) )) (set(output.im, (op name=+ (op name=* (op name=Real(input1)) (op name=Imag(input2)) ) (op name=* (op name=Imag(input1)) (op name=Real(input2)) ) ) )) ) ) / Square(Complex input) -> *(input, input) ( op name=Square type=Complex ( template ID=output (type=Complex ID=input) ) ( rewrite (set (output, (op name=* (input) (input) ) )) ) ) ) - 19 - The Complex object contains two numbers, and implements complex arithmetic. Complex subclasses from Number, because it must be able to rewrite itself into Number objects. Square rewrites itself into Complex, while all the other operators rewrite themselves into Complex or Number. Complex objects must be rewritten into Numbers before their components may be accessed. Thus, we can be sure that all invocations of Complex are eventually rewritten into Number, a primitive class. Note that the definitions for addition and subtraction are redundant. The input declaration section says that a Complex is an aggregation of two Numbers, in order. The operator inheritance mechanism interacts with this declaration to automatically derive the addition and subtraction operators defined above. The 5D system generates an arithmetic tree of primitive objects working from the template patterns in user-defined objects in an iterative algorithm. The program tree Complex C1, C2, C3 label: Real(plus(C3, plus(C1, C2))) Imag(label ^) generates the two Numbers Real(plus(Real(C3), plus(Real(C1), Real(C2)))) Imag(plus(Imag(C3), plus(Imag(C1), Imag(C2)))) which may be fed into I/O operations at the top of the lattice. 4.8.7 _D_r_a_w_a_b_l_e__O_b_j_e_c_t_s The above classes only implement numerical operations. The Drawable class possesses visual properties such as color and position. The position property is a Point. The color property is a Point in RGB color space. A property may be an object, or a arithmetic tree of objects. Property objects can have no properties themselves. The Triangle is a built-in object subclassed off of Drawable. It consists of three Points. Since a Point is composed of three Numbers, a Triangle may have nine arithmetic trees underneath it, and constantly change shape as those subtrees change value. A 3D modelling program might use this to rubber-band changes in a 3D shape in response to numerical input devices, or use feedback to implement jiggly objects. - 20 - 4.9 _P_r_o_g_r_a_m__I_D__S_c_o_p_i_n_g The visibility of IDs is scoped two ways in program trees: by tree structure, and by program source. 4.9.1 _T_r_e_e_-_s_t_r_u_c_t_u_r_e_d__s_c_o_p_i_n_g Outside of a class definition, the ID of a node is visible to a node's siblings and their children. Thus, Inside a class definition, things are different: the inputs and outputs of the object have special IDs, and IDs declared in a method's template are visible within that method's rewrite rule. This allows the template to describe a complex tree, and the rewrite rule to tear it apart and restructure it. 4.9.2 _P_r_o_g_r_a_m_-_s_o_u_r_c_e__s_c_o_p_i_n_g Different sub-trees in the same scene can be downloaded over the network from different applications. If there were just one tree-scoped ID name space, there would be severe problems with different programs innocently (or maliciously) affecting each other's scene members. Thus, ID names are also "sealed off" for each program source. A sub-program from a different network source may only refer to nodes downloaded from that network source, and the primitive objects. A redefinition of a primitive object is also visible, since it is referred to by the name of a primitive object. A parent node may use relative ID addressing to walk a tree down to a child node received over the network. This is only a feasible coding technique if the child tree has been "syntax-checked" against a template. 4.10 _C_l_a_s_s__d_e_f_i_n_i_t_i_o_n__s_c_o_p_i_n_g A class definition occurs under a program tree node. Thus, it is only available under that parent node. Two definitions of the same class may not be siblings. However, a class may be redefined in a child tree. The class redefinition may only have one superclass, the parent definition. The redefinition may add, delete, or change operators or properties. The parent's version of overridden operators may be invoked within more elaborate implementations. For example, the "hinge" operator which connects polygons may be redefined to draw a line along the edge of the hinge, by redefining the class Drawable and overriding the "hinge" definition. In a class definition the operator and property definition nodes may use the Type= to select the special IDs Parent or - 21 - Self. In an operator definition, Self indicates that the type of an operation is that of the class or of any derived subclass. Examination of the Number and Angle classes shows an example of this. The Number operators are defined as type Self. Since Angle derives from Number, all the operators from Number simply appear as "Angle + Angle is Angle" etc. without being respecified in the Angle class definition. Scoping describes which other objects an object definition may refer to. There are four forms of references: rewrite, aggregation, data, and property. Here are the scoping rules for each type of reference: 4.10.1 _R_e_w_r_i_t_e__S_c_o_p_i_n_g Rewrite reference scoping controls what a method definition can rewrite itself into. The example class Complex rewrites itself into Complex or Number. Here are the replacement scoping rules: Self An object may replace an operation on itself with another expression of its own type. For instance, Complex replaces the square(Complex) operation with multiply(input1, input1). Super An object may also replace an operation with an expression of its super-class's type, and on up the line to Object. For instance, Complex replaces the Real and Imag operators with expressions of type Number. Complex cannot replace any invocations with operators of type Object, because Object has no operators. Obviously, if a class can rewrite itself into any other class, a circular definition would cause an operation to be rewritten endlessly. While all such errors can be discovered automatically, it is very difficult to remove them from a design. This rewrite policy avoids this problem entirely by making it impossible for circular references to exist. Note: inside a rewrite rule, all known classes may be used for interior operations. [ I think this deserves its own heading, but I don't know quite where. ] 4.10.2 _A_g_g_r_e_g_a_t_e__S_c_o_p_i_n_g Aggregation reference scoping controls what objects may be input to an operator rule. Above, Complex accepts Complex and Number as input. Here are the aggregation scoping - 22 - rules: Self An object may have objects of its own type as inputs. For instance, Complex accepts square(Complex). Super An object may have objects of its various superclasses as inputs. For instance, the Complex object creation rule accepts two Numbers as inputs and type-casts them into a Complex. Sibling An object may accept _s_i_b_l_i_n_g objects (other objects with the same superclasses) as inputs. In rewrite rules, the special type Parent refers to the parent class from whom an operator was inherited. This is used in operator re-defines in classes which override a parent class of the same name. It allows invoking the parent's operator definition in the middle of the child's operator definition. These rules are somewhat arbitrary. They force the class designer to think through very carefully the objectives of the project, and to understand more fully the "Buddha Nature" of the class structure. 4.10.3 _D_a_t_a__S_c_o_p_i_n_g Each object defined in a Data sections of a class must have an ID which starts with a $ sign. References to ID's starting with $ sign are scoped to within the class definition. [ This is non-orthogonal with the rest of the scoping rules. Do it some other way. Maybe myclass::ID? ] 4.10.4 _P_r_o_p_e_r_t_y__S_c_o_p_i_n_g 4.10.4.1 _P_r_o_p_e_r_t_y__N_a_m_e_s Properties are not subject to a unique name space. Different classes may use the same name to define properties unique to themselves. If two different classes both define a property and are combined to derive a subclass, the two different properties may be disambiguated by the _s_u_p_e_r=ppppaaaarrrreeeennnntttt keyword. The data section of a class definition is private; the properties of aggregated data types are not available. 4.10.4.2 _P_r_o_p_e_r_t_y__T_y_p_e_s Properties may be of any type which has no properties. The issue here is that if a property can have a property, then it can go into a loop attempting to evaluate the original property. Properties are second class citizens in 5D. They - 23 - are intended as simple adornments directing the evaluation of real tree nodes. If a property has important information to contribute to the execution of a program, it should be a real tree node instead. To enforce language simplicity, types of properties may be restricted to something. The siblings of a superclass might work out, as might a special sub-tree of simple types in the core class hierarchy. 4.10.4.3 _P_r_o_p_e_r_t_y__I_n_h_e_r_i_t_a_n_c_e Properties are inherited dynamically, not statically. When trees are executed via pointers, they inherit their properties from the pointing node, not via their original parent. 4.10.5 _A_d_d_r_e_s_s_i_n_g__i_s_s_u_e_s Suppose that sender A creates a tree that accepts data from sender B. B's data may only appear under A's world according to A's wishes. A may not remove B's data directly, _s_i_n_c_e _i_t _c_a_n_n_o_t _a_d_d_r_e_s_s _i_t. However, A must instead remove A's trees which hold B's data. This example brings up another point: dynamic references to a non-existent ID are a run-time error. The Exception class handles this type of problem. The extant expection handler receives the code for a non-existent ID reference, and acts appropriately. Static references are not an error. That is, the disappearance of a named node does not automatically cause exceptions for all the nodes pointing to it. A new version of the node, or another node somewhere else with the same ID, may be interposed without mishap. A remote application which performs this sort of skullduggery should put execution interlocks in place beforehand. Program references may use IDs with relative indexing: an ID may be followed by zero or more /_n_u_m_b_e_r strings, each number an index at successive levels of the tree. Relative indexing only goes down the tree, and ignores network scoping rule. Thus, a program may accept a network packet and peer at its contents. It also allows a complex polyhedron to avoid giving an ID to each component when specifying interconnections, thus saving much space in transmission. 4.10.6 _A_d_d_r_e_s_s_i_n_g__U_s_e_s The ID space is segmented for various "control" trees. For example, one small range of IDs is used inside tree definitions to refer to the inputs of that tree. Another range of IDs is used to indicate shared-memory bitmaps for concurrent access by 5D and a 2D imaging system (X, - 24 - PostScript, video) on the same machine. 5. _L_a_n_g_u_a_g_e__I_m_p_l_e_m_e_n_t_a_t_i_o_n__A_r_c_h_i_t_e_c_t_u_r_e 5D may be fully interpreted, not that you'd want to. A full interpreter can not build a sortable polygon database, and thus cannot implement hidden surfaces. It would also be very slow. A partial interpreter can build a polygon database. This technique analyzes the world description tree and decomposes it into jobs to be done at different times. The section below describes this technique in more detail. The language is also intended to be "hot compiled", that is, the deck software can analyze a tree and generate binary code to implement that tree. If it creates nothing more than a string of subroutine calls to the op-code handlers of the interpreter, it still dissolves away the interpretive loop. A compiler can optimize different built-in types; i.e. it can do constant folding for matric operations for which portions of a matrix are known. 5D is also targeted for ease of compilation on parallel processors. The language attempts to minimize interactions between nodes. [ This will require much analysis by experts in parallel software. ] 5.1 _L_a_n_g_u_a_g_e__d_e_s_i_g_n__i_s_s_u_e_s 5D is intended as a basis for real-time simulation. As such, the power and elegance of abstract research languages is unfortunately not available. Languages such as Smalltalk, Prolog, Actor, etc. are beautifully simple and dense, but require unpredictable amounts of CPU time to implement their constructs. 5D's language constructs must be implementable in a predictable manner. Every operation must require O(1) amount of time to execute. 5D is designed to be efficient in the amount of space used to store 5D programs, and thus efficent in network transmission time. It is also designed to be efficient to execute compiled or digested 5D code. After the simulation clock starts, 5D must keep the beat. Slow digestion of 5D code, and the prodigious use of RAM to store pre-computed data, is unfortunate but necessary. Also, real-time predictability outvotes run-time efficiency. For example, whether it would be more efficient to use garbage collection rather than freeing memory on the fly is immaterial. The screen cannot stop updating at random intervals to do a GC sweep. - 25 - 5.2 _L_o_w_-_e_n_d__s_y_s_t_e_m__i_m_p_l_e_m_e_n_t_a_t_i_o_n__s_t_r_a_t_e_g_y 5D is targeted initially at low-MIPS desktop computers such as the 386 PC and the Mac. A single-CPU frame buffer-based computer will implement 5D as a classic simulation system. A multi-tasking co-routine package supports a variety of subsystems which implement different aspects of the deck: sound I/O, positional input devices, force-feedback events, network I/O, and last but not least, screen update. These subsystems sleep on different events: I/O interrupts, timeouts, and software-defined events. Each subsystem maintains a task list. It sleeps on one or more events and does a task list each time that event occurs. The network I/O system accepts trees from outside and adds them to the world tree. Each subsystem must be able to insert new tasks and delete old tasks on the fly, in response to dynamic editing of the tree. The polygon database has 2 levels: +o a list of high-level objects which can change their relative distances and orientations, +o where each object is solid and does not change shape. The high-level list must be sorted for each mono or stereo screen refresh. Each static object is stored in a Binary Space Partition database [ ref ]. (The BSP algorithm does a large majority of the polygon sorting work independent of the viewpoint. Animating a static object consists of pre- sorting it, then walking the last mile over and over, thus considerably speeding up screen refreshes.) Each screen refresh must sort the list of high-level objects in 3-space (probably by bounding boxes), and do a fast BSP viewpoint of the polygons in each static object. Depending on the screen size and scene complexity, object-first or scan-line-first rendering may be appropriate, and the renderer may want to switch between them dynamically. For stereo rendering it may make sense to walk through the database rendering both screens, or to walk through it twice doing one screen at a time. Practical experience [ref: Graphics Interface '90, "The DataPaper", Green & Shaw] shows that applying BSP to a completely static scene winds up fracturing the scene into an immense number of polygons, and in fact the 2-level scheme ("clumpy BSP?") is preferable in this case also. In any event, the Graphics Gems software distribution and the VOGLE portable 3D library will provide the source code for the first pass at a renderer. - 26 - 5.2.1 _S_t_a_t_e__V_e_c_t_o_r_s For debugging worlds, and doing animation, it is necessary to maintain a state vector of the execution of a world. Network control can stop and start execution, and "play" the sequence of frames forward and back. Because tree evaluations are triggered by multiple clocks and asynchronous events, there is not one state vector, but instead a "time line" of events and state vectors for the appropriate tree. [This is going to be hairy!] These state vectors are accessible to 5D and are used by the World Manager to "swap out" world descriptions as the user wanders between them. 5.3 _N_e_t_w_o_r_k__C_o_m_m_u_n_i_c_a_t_i_o_n_s A 5D program is read in from a file or a network connection. Decks communicate across networks by sending 5D trees. Communication circuits are point-to-point in 5D terms but may be multi-drop underneath. That is, it may receive UDP broadcasts but only receives from host X under host X's connection object. Thus, it must have a separate UDP broadcast connection object for each incoming host. When received, a tree may be examined and then executed or rejected, or it may just sit in a holding place for reference. The World Manager needs to accept downloaded trees and splice them under a "top of world" partition. MazeWar merely needs to examine the latest status message from all other players. Trees are examined with the 5D _t_e_m_p_l_a_t_e facility: a received tree may be checked against a template as a form of syntax check. If it passes the check, the receiving parent tree may choose to execute it. [ We may want to add the boolean Authenticated as a property of a received program. The receiver can then take various actions if a program did not have the right magic encrypted checksum. ] Groupware and Cyberspace applications are not well served by the common network protocols; 5D may eventually include a mutated form of ISIS, IRC, Kerberos, MUD, or all four. MUD would form a nice permanent object repository for 5D, while something like the Habitat system could be built running 5D over IRC. 5.3.1 _R_P_C__c_o_m_p_i_l_e_r For doing basic application-deck pair applications, a library-building compiler like the one SUN distributes with NeWS would be very useful. [ I read about it in a SUN tech papers book: I haven't actually used it. ] - 27 - 5.3.2 _C_C_K_:__C_y_b_e_r_s_p_a_c_e__C_o_n_s_t_r_u_c_t_i_o_n__K_i_t The effort involved in debugging a client-server network protocol is surprisingly large; we're going to need a protocol design & debug system for doing many-to-many 5D network applications. It should have a method for tracing network messages to & from a deck, and stopping & starting operations via network control. ESTELLE [ ref ??? ] is a protocol design language used for describing portions of the OSI protocol stack. There are ESTELLE simulators; this would make a handy addition to the CCK. 5.3.3 _N_e_t_w_o_r_k__O_b_j_e_c_t The Network object is an abstract superclass for defining network protocols for use with 5D. The object has a channel number as a property. Each network connection has a unique number. This number is used to multiplex communications between multiple endpoints in the deck to the outside world. Whether a network port initiates or receives connections is a property, as is whether the protocol uses reliable and ordered delivery. A networked deck starts up with various tasks such as calibrating I/O devices and adjusting speaker volumes. It then starts a program tree whose sole purpose is to open a receptive network connection in each protocol the deck supports. 5.3.3.1 _T_C_P_/_U_D_P__n_e_t_w_o_r_k_i_n_g 5D uses RFC [ XXX ] to dynamically register the well-known TCP & UDP port numbers for these main ports. It can also assign channel numbers to subsidiary network sockets dynamically. Any program when creates subsidiary sockets with auto-assigned channels must upload the trees with the sockets, to find out their protocol port numbers. A program may also pre-assign port numbers and hope it won't clash with anything else. This technique must be used in UDP broadcast applications like MazeWar, because every deck must use the same port number. [ A reliable broadcast protocol could be done by relying on a main application to ensure that all other decks got your message, and simply making sure that the main application got it. This follows the dictum of philosophy of off- loading non-interactive work to the application. ] 5.4 _W_o_r_l_d__M_a_n_a_g_e_r The World Manager is just the main 5D application. It makes sub-worlds available to the user. A static WM is loaded from a file and stores one or more sub-worlds in memory. - 28 - 5.4.1 _H_a_l_l_w_a_y The prototype implementation of the WM is the _H_a_l_l_w_a_y (inspired by various "Rooms" systems). The user moves down a hallway of doors. Each door has some label or icon. The user selects the doorknob, label, or icon and pops into that world. Under file-based 5D, the world is just there in RAM, waiting to run. Under network-based 5D, there is usually a remote application program on a computer for each world. This application handles permanent data storage and complex calculation work not easily done with 5D. In general, the application communicates asynchronously with the world, implementing all synchronous user interface feedback in downloaded 5D. 5.4.2 _N_e_t_w_o_r_k_e_d__W_M A dynamic networked WM downloads world trees across the network from a remote master program for this deck. In the Hallway, selecting the doorknob causes your WM to send a message to the master, which then fires up the program for your selected world. The program contacts your WM and downloads the world tree. The WM accepts the world, stuffs it under a "top-of-world" (class Void) node, and turns it on. When you exit the world, the WM can destroy it or keep it around. The WM can manage memory usage by uploading the current state of a world to its counterpart and deleting it. When you want to re-enter it, the WM downloads it again. Before this, the WM may "swap out" your previous world. You may only traverse worlds by passing through the Hallway. There's no technical reason for this, it's merely because the Hallway's worlds are not conceptually connected. A world may implement its own suite of connected environments and traverse them in any order. A house may have doors, windows, ventilator shafts and secret passages for you to traverse. 6. _T_e_x_t 5D does not contain a textual abstraction, a font database, or support for typewriter keyboards. There are two possible uses for text in 5D: 2-dimensional text and 3-dimensional text, with very different aims. Statistically speaking, 2D text is rendered, read, and erased. 3D text, on the other hand, tends to be permanent. It is generally used as a label in a larger 3D model. The low volatility of 3D text - 29 - does not merit devoting scarce permanent deck resources to fonts. It is better handled as a library tree used by applications. 2D text is not supported for 2 reasons: +o 2D textual graphics has been addressed already by many systems: Tex/Dvi, Postscript, troff, the X Window System, etc. Many of these systems have freeware versions which could be easily altered to support 2D graphics under 5D. In particular, it would be quite easy to create an X window server which moves flat bitmaps around in 3-space. This could be connected to 5D via 5D networking or by cohabiting in the same operating system. A multi-processor Mach system with one CPU running the X stuff and one running 5D would make a great hypermedia system. (Throw another CPU on the fire!) +o The "official" 5D core language specification only supports application features which are widely recognized as the one right way to do things, or as one of two or three commonly accepted methods. Text is a mess. There are upwards of 20 European Roman-Arabic keyboards alone. Japan has 3 alphabets. Some lettering goes right-to-left, some up-to-down. Calligraphic lettering apparently requires an iterative method to match up lines between symbols. We don't want to keep adding new text "standards" every six months, duplicating the work that's been done for other text-processing systems. If the specified functionality of a low-end deck ends up including a CD-ROM of library materials, the core library will include the Hershey fonts, and some basic Adobe-style outline fonts, and simple 3D CSG-based text construction operators. [It might work out for keyboards to just be objects with many, many switches. Another object might interpret these into an ASCII dataset, for network communication.] 7. _T_e_r_r_a_F_o_r_m_e_r The TTTTeeeerrrrrrrraaaaFFFFoooorrrrmmmmeeeerrrr is a visual programming CASE system for 5D trees. It is a 5D program which presents a tree as a 3D scene, using translucent structure blocks to display several levels of structure simultaneously. Someday. But for now, it's a standard 2D window system application. You are able to browse and edit the program tree, and browse the class inheritance lattice. The tree and lattice windows - 30 - use a space-efficient method to display these data structures. 7.1 _T_r_e_e__w_i_n_d_o_w The tree window show many levels of a tree, starting at a particular node in the tree. The tree (+ ID=sum (*(1,2),3)) is shown as: ------------------------------------------------------ | + sum | | -------------------------------------------------- | | | * | | | | ---------------------------------------------- | | | | | 1 | | | | | ---------------------------------------------- | | | | ---------------------------------------------- | | | | | 2 | | | | | ---------------------------------------------- | | | -------------------------------------------------- | | -------------------------------------------------- | | | 3 | | | -------------------------------------------------- | ------------------------------------------------------ This format can not show all the nodes in a 5D program. Grasp the edge of a box with the mouse and move it outwards to "zoom in" on that box, or move it inwards to move up the tree. There are two or more tree windows. You may "cut" or "copy" a tree in one window, and copy it to the other one. If a node has off-screen parents or children, its box is drawn differently, alerting you that there is more. 7.2 _N_o_d_e__W_i_n_d_o_w When you select a tree node, you may view that node in full in the node window. This window shows all the keywords interpreted appropriately, and all extant properties. 7.3 _T_r_e_e__t_y_p_e_s The 5D text format includes the ability to include files. These include commands should be preprocessed before a tree is downloaded, unless the deck possesses access to a universal file name space. - 31 - TF allows you to specify that the contents of a sub-tree adhere to a given subset of 5D node types, via the template mechanism. TF saves this non-program information as comments in the source, via text comments starting with "_F_o_r_m_a_t:", to remember in a later session how you wish to view your programs. It can translate other formats into 5D format, allow you to edit the resulting tree, and save it out in any format. Also, if configured correctly, TF can invoke an appropriate editor. You would probably wish to use a real 3D modeller to edit a 3D model instead of editing the 5D tree; ordinary differential equations are much more tractable in the form xxxx'''' ==== xxxx ++++ yyyy yyyy'''' ==== ----xxxx ++++ yyyy than as the equivalent 5D format. 7.4 _C_l_a_s_s__L_a_t_t_i_c_e__B_r_o_w_s_e_r You may browse the class inheritance lattice via the class browser window. Of course, you may not edit the class inheritance lattice directly. The lattice is displayed using Venn diagram boxes. A series of class definitions, where abstract superclasses and type-bearing classes are named appropriately: (class ID=abstract1) (class ID=abstract2) (class ID=atype super=abstract1 super=abstract2 ) would display in the class lattice browser: - 32 - ------------------------------------------------------ | ------------------------------ | | | abstract1 | | | | | | | | | | | | ------------------------------- | | | | | | | | | | atype | | | | | | | | | | -------------------|---------- | | | | | | | | | | | | abstract2 | | | ------------------------------- | ------------------------------------------------------ The browser window cannot display the entire class lattice. It does not attempt to show all possible intersections, nor even all the intersections of a particular superclass. If a class has any unseen intersections, the border of its box is different (monochrome) or its name is in a different color. Classes with no on-screen children are not drawn with their own box, but if they have children they are underlined or drawn in color. This is simply to avoid screen clutter, or "non-data ink". [ Envisioning Information, Edward Tufte. ] To look at all intersections of a superclass, select that class. To select a subset of the intersections of one or more classes, mouse-down in one intersection box and drag the mouse through all intersections in which you are interested. Since this is a Venn diagram, neighboring boxes form a simplified Boolean expression. 7.5 _O_p_e_r_a_t_o_r_s The operator menu gives a list of defined operators. It can give a list of all operators, operators unique to one class, or multiply defined operators. 7.6 _A_d_d_r_e_s_s__n_o_d_e_s Address nodes are marked, but automatically are drawn in the type of the node they point to.