Prograph 1.1
Volume Number: 5
Issue Number: 7
Column Tag: Mac OOPS
Prograph Raises OOP To New Height 
By Mark Szpakowski, Nova Scotia, Canada
Introducing Prograph
Prograph is a very high-level, pictorial, object-oriented programming language
and environment, with integrated Application Builder for easily creating all the
components of a Mac interface. Although new as a deliverable implementation, the
language, under development since 1982, is rich and expressive, an inheritor of the
Lisp, Prolog and Smalltalk traditions. The Prograph 1.2 Editor/Interpreter is
available now for $195 from The Gunakara Sun Systems of Halifax, Nova Scotia,
Canada.
Prograph is thoroughly pictorial -- text is used only for names and for
comments, and serves no syntactic or semantic function. Prograph’s dataflow-style
design diagrams are the source code -- they are immediately executable, and may be
animated to display execution progressing through them. This makes debugging easy
and intuitive. Prograph 1.2 fully supports the single-inheritance model of Object
Oriented Programming (OOP) in a visual manner that preserves OOP’s inherent
simplicity and naturalness. Like NeXT’s NeXT Step environment, Prograph provides a
set of inheritable classes with automatic event handling and associated WYSIWYG
graphic editors for creating menus, menu items, windows, and window items. In
addition, Macintosh Toolbox calls, with names exactly as used in Inside Macintosh, may
be made from Prograph.
Prograph is thus an environment both for the hacker who needs to get into the
nitty-gritty of the Macintosh and for the user who wants to create Mac-style
applications without having to master 5 volumes of Inside Macintosh. Both types will
find that, after some exposure to Prograph, moving back to a purely textual language is
like moving back from a Mac interface to a line-oriented one. You’ve been warned!
Fig. 1 Prograph’s Opening Screen
Dataflow Pictorial Programming
In this article I’ll introduce the “look and feel” of Prograph programming,
describing both the language and the environment. When Prograph starts up, it
displays two windows, a Classes window and a Universal window. We’ll get to the
Classes window later. The Universal window is used for defining methods which are
not specific to any class (universal methods). A method is roughly equivalent to a
procedure or multi-valued function -- it performs some action, taking 0 or more
inputs and returning 0 or more outputs. To create a method, click in unoccupied space
(click-space) in the Universal window: a new, unnamed method icon appears. This is
a general principle in Prograph: clicking-space in a window creates an object
appropriate to that window.
Fig. 2 An Unnamed Method Icon
An insertion point below the icon permits immediate typing of a name for the
method. Command-clicking on the icon opens another insertion point, for typing a
multi-line comment. This comment may be moved, follows its method icon when that
is dragged, may be hidden or displayed at will (by command-clicking), and will appear
in Prograph’s Info windows when that method is selected there. Comments may also be
hidden or shown for a window as a whole. Comments may be attached to most icons in
Prograph, making it largely self-documenting.
Fig. 3 Method with name and comment
Double-clicking on the method icon will open a window onto its structure. The
“stacked” shape of the icon is meant to suggest that a method consists of a series of
cases. Execution in a method begins with the first case, and will either proceed
through the first case or go on to the next, depending on whether controls attached to
operations within the case have or have not fired. The window banner gives the method
name, the current case number, and the total number of cases in that method (as in
show screen size 1:1 below). The icons between the name and the zoom box are used
for navigating between cases.
Fig. 4 Case Window with Un-named Oper
Each case has an input bar and an output bar, on which inputs and outputs
accumulate. Data in general flows from top to bottom, from the input bar, through
operations, to the output bar. An operation is created by clicking-space in a Case
window, resulting in an un-named operation icon appearing, with an insertion point
within it for typing its name. This name may be typed in, or it may be transferred
into the selected icon from any of several scrolling lists of names accessed via the Info
menu. Typos may thus be completely eliminated. Lists are available for Prograph
primitives; Mac Toolbox calls, globals, constants, etc; and classes, attributes and
methods, whether these are system-supplied or created by the user.
Fig. 5 User-defined operation, primitive, constant, and comments
Hitting return after a name has been supplied causes Prograph to supply the icon
with its default arity (inputs and outputs), as represented by terminals just above the
operation icon, and roots (sources of data) just below the oper. In Fig. 5, show is a
primitive, visually distinguished from a user-defined operation screen size by the
line on the bottom end of the icon. A datalink is created by selecting a root, holding
down the option key, and then clicking on a terminal (e.g., the two datalinks between
screen size and show). The screen size operation will return two numbers (for the
screen right and bottom coordinates). These will flow into the show primitive, which
concatenates its inputs and displays them in a dialog window. The constant “, “ will
appear between the two coordinates. Thus the result of executing this should be that,
for example, the string “640, 480” (depending on the monitor) will be displayed.
Double-clicking on the show icon will open an info dialog, giving the
documentation on that primitive: a brief description of what it does, what inputs and
outputs it expects and what their types are. Double-clicking on a user-defined
operation icon, such as screen size, will open the first case window of the method it
calls if it exists, or, if it doesn’t yet exist, will open a new case window so that
definition of that method can begin.
Note that we’ve attached comments to the two roots of screen size. When we
double-click on screen size to create its first case window, those comments will also
appear on the output bar of the screen size method.
Fig. 6 Mac Global and 3 Mac Get Fields
The screen size method begins by taking the bit map stored in the screenBits Mac
Global, extracts its bounding rectangle by way of the bounds Mac Get Field, and then
gets the right and bottom coordinates from that, with the results flowing out the output
bar. Note the inherent parallelism: the right and bottom operations could execute in
parallel on a parallel machine. Prograph’s Opers menu has menu items for
transforming operations into Macintosh Toolbox calls. Double-clicking on a Mac
operation icon opens an Info dialog which provides type information on the operation’s
inputs and outputs.
Executing and Debugging
Fig. 7 Executing a method
To execute the show screen size method, one simply selects its icon in the
Universal methods window (or else makes sure its case window is the current front
window) and selects Execute Method from the Execution menu. A dialog will appear,
displaying “640, 480”.
Fig. 8 An Execution Window
Selecting Step/Show On from the Execution menu with screen size selected (or
frontmost) puts it into single step mode, with its case window visible during
execution. The dotted background indicates that it’s an execution window, as opposed to
an editing window. When execution reaches this method it will pause; hitting return
will cause execution to proceed on step at a time. Already executed operations, roots,
and terminals are displayed normally. The next operation to executed is highlighted.
Operations still pending are shown grayed-out. Double-clicking on a root or terminal
opens a window onto the data value at that point. If the value is changed, execution will
roll back to accommodate the change, and then continue forward again. Double-clicking
on the dotted background opens an editing version of the window, where changes can be
made in the design diagram itself. When execution resumes, it will roll back to the
point of change, and then continue from that point.
If an error occurs during execution, Prograph beeps twice, and opens an
execution window onto the case where the error occurred, with the offending operation
highlighted. Selecting Last Error from the Info menu gives information on the nature
of the error. A stack window may also be opened, displaying icons of methods as they
call other methods. The stack may be popped, or icons double-clicked to open execution
windows onto methods on the stack.
Fig. 9 Renowned recursive factorial function with stack window
The factorial function in Fig. 9 illustrates how cases are used. Factorial expects
a positive integer as input. Case 1 takes this input and compares it to 1 via the match
operation (the 1 with the bar above it). A match either succeeds or fails. The little
square attached to the right of the match is a control, with the X within it indicating
that the control will activate on failure of the match. A check mark () within a
control means it activates on success of its attached operation. Here the control is
“Next case on failure”: i.e., if the input data does not match with 1, go on to the next
case. If it does match with 1, the input data is simply passed on to the output (factorial
of 1 is 1).
Case 2 of factorial takes the input, decrements it (the -1 operation),
recursively takes factorial of that, and multiplies the result by the input (factorial of
n is n times factorial of (n - 1)).
As factorial executes, its progress may be observed in the stack window. The
numbers within the method icons indicate which case of that method is executing.
Multiplexes and Controls
Here is another example which will illustrate both controls and mutliplexes.
Multiplexes are annotations applied to primitives or to user-defined operations which
transform them into list-processing, iterative, or looping operations. I.e., the
operation applies itself to each of the elements of a list, or loops until some control
causes it to terminate. In this example a dialog with three buttons is put up; pressing
the first two evokes some response, with the dialog coming up again, while pressing
the third, Cancel, button terminates the whole thing.
First thing we do is to create a method, called Marx Bro’s, consisting of a single
operation, called about Marx. This operation has been annotated as a Repeat, via the
Repeat menu item in the Controls menu. Repeat will continue executing until a
Terminate or Finish control within it fires.
Fig. 10 A Repeat-Annotated Operation
To create the about Marx method, double-click on the left side of the about Marx
method call. Its first case window opens up, and the method can be defined as in Fig.
11. The answer primitive is just like its HyperTalk namesake: the first input is a
prompt, with up to three other inputs specifying button names. The text of the button
clicked flows down to the respond method.
Fig. 11 A “Terminate on Failure” Control
Selecting the respond oper, and annotating it with Terminate from the Controls
menu attaches a “Terminate on Failure” control to it. This control means “stop the
current multiplex operation immediately, and return whatever (if anything) was on
the output bar on the last successful iteration of this multiplex”. There is a related
control called Finish which first finishes execution of the current case, returning
whatever is on its output bar, before halting the multiplex. Double-clicking on the
respond oper now lets us define it.
Case 1 of respond checks if the input matches with “Harpo”. If not, it goes on to
the next case (”Next Case on Failure”); if so, it feeds the phrase “the clown” into the
show primitive, which displays it. The about Marx method now re-executes. Case 2
does the same for Groucho, using the phrase “Cigar!”. Case 3 will only be reached if
the user pressed neither the Harpo nor the Groucho button (i.e., Cancel must have been
pressed). It does nothing at all, except that when execution reaches the output bar, the
“Failure” control attached to its right end will fire. The check-mark on the control
means that it fires on success of its attached operation (here, the output bar). The
failure will be propagated to the calling operation, the respond operation in the about
Marx method. So when Cancel is clicked, respond will fail, and, since it has an attached
“terminate on failure” control, that control will fire, terminating repetition of the
about Marx method.
Fig. 12 3 Cases, and a “Failure” Control
Fig. 13 “Fail on failure” Control
Fig. 13 illustrates a more economical way of doing the same thing: attaching a
“Fail on failure” control to the Groucho match makes the third case unnecessary. If
the button clicked is neither Harpo nor Groucho, the Fail control is triggered, causing
respond to fail, causing its Terminate control to fire, ending the loop. This just gives a
taste of the power of Prograph’s annotations (cf. Fig. 14).
Fig. 14 Opers and Controls Menu
Classes, Objects, Attributes, Methods
We now turn to classes. A click-space in the Classes window creates a new class
icon, which, as usual, can be named and commented. Selecting a class and then
option-click-spacing creates a new subclass, connected to its parent by an
“inheritance arc”. The subclass inherits the attributes (equivalent to class and
instance variables in Smalltalk) and methods of its parent. Class hierarchies are thus
defined in Prograph the way they usually are on a napkin over coffee, by simply
drawing the class hierarchy tree. Fig. 15 shows a small class hierarchy.
A class icon has two sides. Clicking on the left side opens the class’s Attributes
window, where its attributes can be defined and edited, while clicking on the right side
opens its Methods window.
Class attributes, which have one value for the class as a whole, are displayed
above the fuzzy line in the Attributes window (cf. the person attributes window),
while instance attributes, whose values may vary with each instance of a class, are
displayed below the line. Instance attributes are represented as triangular icons, and
class attributes as hexagonal icons. The attribute’s name is below the icon, while its
default value, or the class of its value if that value is a class instance, is indicated
above the icon. Inherited attributes are displayed with a downward pointing arrow
within their icons (cf. the student attributes window).
Fig. 15 Classes and attributes windows
An object (an instance of a class) is created by an Instance annotated operation.
This simply produces a default instance of the class whose name it bears. The object
will appear on the root of the instance oper, ready to flow into other operations.
Making an object is thus a snap in Prograph: click-space in a Case window, annotate
with Instance from the Opers menu, give the oper the name of a class, and Execute:
bang, an object flashes in and out of existence. It flashes out of existence because if it