[sci.virtual-worlds] 5D Design: Part 2 of 4

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.