Designing new Types

ABC is object-oriented, meaning that everything you work with is an object. Objects are entities which have parts and behavior. They can be simple entities like integers, reals, or strings, or more complex entities like dictionaries, widgets or managers.

To specify the parts and behavior for an object, a type must be defined. For example, the existing type Integer specifies that all integers have a value and can perform operations like addition and subtraction. The integer 4 and the integer 44 are different integer objects with different values, but both perform the same addition defined in Type Integer because they are of the same type. they are said to be instances of Type Integer.

New functionality is added to ABC primarily through the design of new types. In this chapter, you will be shown how to specify a new type.

Type Format

The figure below shows the text definition of a type Stack. The operation of a stack is to push and pop objects on the stack in first-in-first-out order.

    TYPENAME Stack
    PARENT Partslist
    PARTS
    { data:Array
      top:Integer
    }
    TYPEMETHODS
    { new initsize:Integer
        { newstack -> me new.
          (initsize < 1) then 
          { SIGNAL "Initial stack size must be greater than 0.".
          }.
          newstack's top -> 0. 
          newstack's data -> Array newSize initsize.
          REPLY newstack.
        }
    }
    INSTANCEMETHODS
    { push anElement:Object
        { top ++; size -> data size.
          (top > size) then 
          { !! stack is full so double it
            data -> data resizeBy size.
          }.
          data at top put anElement.
        }
      pop
        REPLY Object
        { (top > 0) then 
          { anElement -> data at top; top --.
            REPLY anElement.
          } else 
          { SIGNAL "Stack is empty.".
          }.
        }
      top
        REPLY Object
        { (top > 0) then 
          { REPLY data at top.
          } else 
          { SIGNAL "Stack is empty".
          }.
        }
      isEmpty
        REPLY Boolean
        { REPLY top = 0.
        }
    }

Each type requires a name and a parent type. Specifying the parent type to be Partslist means that a Stack has the same parts and is able to process the same methods as a Partslist. All the types you design should have at least Partslist as a parent. The type Partslist lets you access the parts directly, copy parts from one object to another and interactively edit an object.

In the example, objects of Type Stack are said to inherit from Type Partslist. In the same manner, Type Partslist has a parent of Object. Therfore, by defining Type Stack as having a parent of Partslist, it will automatically inherits all of the parts and capabilities of PartsList and Object.

The structure of a type is defined by its parts. Stack defines two parts: 'data' and 'top'. 'data' is an array which holds the objects currently on the stack, and 'top' indicates which element is on top. For efficiency, this implementation does not shrink 'data' when an element is popped, so the top marker may not be the end of the array. Also, if an element is pushed on a full stack, the data array is doubled in size.

Once the definition of Stack is known by ABC, stack instances may be created. The following statements show how a stack might be used:

stk -> Stack new 10. stk push 5. i -> stk pop.

The first step is to actually create a stack as shown in the first line. Note that since Stack is now a type, the name 'Stack' is reserved to refer to the type called Stack. Thus, a new stack can be created by executing new: from type Stack. Since 'Stack' is a type, the list of TYPEMETHODS for Stack will be searched for method new:. The method will execute, creating a new stack, initializing the parts and REPLYing with an instance of a Stack. Once the variable 'stk' refers to this instance, the push: and pop methods may be executed. These methods are found in the INSTANCEMETHODS section of Stack.

If an instance method is not found in the current type, a search will be made in the instance methods of its parent. The search will continue until type Object is searched. An exception will be generated if the method is not found in Object.

If a type method is not found in the current type, a search will be made in the type methods of its parent. The search will continue until type Object is searched. If not found, the type methods of Type Type will be searched and finally, the instance methods of Object. An exception will be generated if the method is not found.

ASM Methods

It is sometimes advantageous to avoid calling a method at runtime for performance reasons or to call primitive functions. This can be accomplished by defining an ASM method. An example is the Boolean {it whileDo:} as shown below.

    whileDo aBlock:Block
       ASM
       { { START.
           BRF END.
           %load aBlock.
           %load me.
           BRU START.
           END.
         }.
         PUF.
       }

For most method calls, ABC substitutes code at compile-time to run the appropriate method at run-time. However, If an ASM method is encountered, the associated ASM code is inserted at compile-time and no method need be called at run-time. While the details of specifying ASM methods are given in the ABC Assembler manual, you should note that an ASM method begins with the ASM keyword followed by assembler statements between brackets. The %load commands insert the assemble code to compute the specified variable at their respective locations. All ASM methods begin with an implicit '%load me'. For more information, see the ABC Assembler manual.

There are times when the ASM version is inappropriate because the variable may refer to different types during execution. This can be a problem since the actual method has been converted to assembly code at compile-time so the correct code will not be executed. The ':?' notation mentioned in the previous chapter will direct ABC to not use the ASM option but actually call the appropriate method at runtime.

Designing Types Outside ABC

ABC provides the ability to compile your type definitions externally. You may prefer to use a higher function texteditor than is available in ABC or you might like to share ideas with others before building objects in the environment. It also may be possible that a colleague has sent you the source code for a type or method and you would like to add it to your environment. This can all be done by using the external ABC compiler.

To use the compiler, first enter the source code in a source file using any text editor. The source code may be a whole type or a single method. To compile it, issue the command:

% abccomp newtype.type

where abccomp calls the ABC compiler and newtype.type is the file containing your source code. It is recommended that your files be named with a file type of 'type' or 'method' to better indicate their contents. The source code will be compiled and any errors reported.

The compiler will generate a newtype.def file and a newtype.asm file. The .def file contains a definition of the parts and methods for the type and is used by the compiler when objects of that type are referenced in methods. The .asm file is the code which will be imported into the environment (see the next section for information on Import). Anytime the compiler needs to compile a method which has a method to an object of type X, it looks for a file called X.def in the current directory. If it is not found, it will look in the ABCDEF directory. If it is not there, an error will be reported.

Only an .asm file is generated when a method is compiled. In this case, all you need to be concerned with is the syntax and semantics of the method. Of course, you cannot refer to any object types which do not have a .def file. If you want to make a type generally available, you should move the .def file to the ABCDEF directory when its development is complete.

The full form of the abccomp command is

abccomp [-a][-l listfile][-e errorfile][-i][-t typename] filename

where the square brackets indicate optional arguments.

The meaning of the flags are as follows:

-a
don't generate an asm file

-l
format the input and put it in the specified listfile

-e
put the errors in the specified error file

-i
treat the source file as a type method (methods only)

-t
treat the source file as a method of specified typename (methods only)

Designing Types Inside ABC

The Type Manager is used to design types and is activated by choosing the Run/Edit Types option from the ABC MenuBar. You should see the dialog below.

To edit a type, click on a type name in the Types Listbox of the Type Manager. The parts and the instance methods for the selected type will be displayed in the other two listboxes. Type methods can be displayed by selecting the Method/List/Type option on the Type Manager MenuBar. A hierarchical display of types can be shown by selecting Type/List/Hierachical. You may wish to select Stack to see the corresponding type definition for Stack in the Type Manager.

To add a new type select Type/New. To edit an existing one, click on its name and select Type/Edit. Enter the appropriate Parent type and Parts and then click on Apply. If you change an existing type, the system will have to change all instances of that type and recompile any associated methods. This can take a minute or so.

To edit an existing method, double-click on the name. After you have changed the code, select Compile. The development of methods for types is identical to the process for developing other methods.

The remaining options in the menu are self-explanatory. If you delete a method or type, Undo is available to restore the deleted object. Options are available to format the source code and store it in an external file. In addition, you may copy any text and view more than one method or type at a time as well as verify a type.