Prograph:
A Visual Programming Language
|
David
Heise |
& |
Tomas
Joyner |
|
dheise@cs.byu.edu |
|
tomasjoyner@yahoo.com |
EECS
330: Introduction to Programming Languages
Fall
2004
Visual Programming Languages:
For years, programmers have interacted with their computers via a command prompt. Programs were run, and windows were opened, one line at a time. Then came the revolution. When a GUI was applied to an operating system, things began to change. The visual representation of file structures became more relevant. Navigating the system and its commands became trivial. People who ten years before would not even approach the seemingly magical box were now classified as “users”. As a direct result of the GUI upgrade, the computer has become a staple in every home.
There is a similar tremor in the waters of the programming world. Often, when handed a problem, a programmer first determines a sort of flow chart for the program's functionality. The programmer must then translate the visual concept into textual code. This mapping typically proves difficult due to “the use of a one-dimensional textual formalism to represent a multi-dimensional process”[1]. The solution in the works is Visual Programming Languages. Like Windows to DOS, so is Visual Programming to traditional text-based languages.
There has been theoretical work on Visual Programming since the late 60's. Some of the thinking of yesteryear has come to fruition in the form of GPL, LabVIEW, APPWare, and Prograph, among others.
A Brief
History:
As with the creation of most Visual Programming Languages, Prograph was formed with the intent of making programming easier for the programmer. Prograph graphically shows data movement. In this respect it differs from languages such as C and Java, whose focus is on control passing – that is, stepping through a series of commands.
Prograph was conceived in 1983 as the brainchild of Tomasz Pietrzykowski
and Philip T. Cox. While Pietrzykowski
soon moved on to other projects, Cox stayed with the language adding
improvements over the years. In '85
Prograph was distributed with the additional feature of a compiler. When Object-Oriented Programming became the
big buzz, Cox announced the advantages of Prograph's modularity and Object
abilities.
Prograph hit the markets and was used for various applications, though
primarily distributed on the Macintosh.
Games, HTML editors, and spreadsheets have all claimed primary usage of
the graphical language. Businesses also
turned to Prograph for some in-house applications.
Today Prograph is dead.
Programming software for Prograph is still existent, and sold, but the
language has grown stagnant. Pictorius,
the primary distributor of Prograph (with Cox at the head), went under in
1996.
The Prograph
Language:
Prograph is a functional
language. It's data flow can be compared
to Scheme's (or any other functional language) with the primary difference that
the programmer does not have to keep track of parenthesis. Prograph use is simple: data is represented
with lines and methods are various boxes.
Each box contains nodes for inputs (terminals) and outputs (roots). Prograph methods have more than just variable
arity; they also have output arity. The
methods have an I->O mapping from one or more inputs (I) to one or more
outputs (O).
The data in Prograph is passed by value. This enables several methods the use of a single output from another method. These receiving methods can then be run in parallel without one method altering the data in another. This feature will find its usefulness if ever the von Neumann model for parallel processing is upgraded to its more visionary counterparts.
Heretofore, method inputs and
outputs have been referred to as data as opposed to variables. Strictly speaking, Prograph does not have
variables. Inputs and outputs are named
only as a convenience to the programmer.
A consequences of this is lower overhead for a method's environment (if
there are no variables, there is no need for an environment). Scoping, in this context, becomes
irrelevant.
Object-Oriented
Programming comes naturally with Prograph's modularity. A class is defined just as readily as a
persistent, and is still visually expressive.
A class contains methods and variables.
In this case, variables are simply persistents with another name. Inheritance is easily shown via a line from
the parent class to the child class.
Learning to use Prograph is time consuming. After getting acquainted with the graphical nature of the language, the programmer must then prepare for the challenge associated with learning the variety of constructs. On top of that, some universal constructs (such as conditionals) have their own Prograph version that requires attention. The conditional, for example, has 16 different possible implementations.
The greatest disadvantage of programming in Prograph is the challenge of all Visual Programming Languages: spaghetti code. For a simple program with 15 methods, each with three inputs and three outputs, the potential for readability loss is great. This difficulty is overcome with experience. In practice, Prograph is quite readable (perhaps “viewable” would be more descriptive).
Constructs and Syntax
![]()
In Prograph there exits 9 basic constructs, 6 external
constructs, 4 main constructs, and 10 control constructs. These constructs, in
addition to the other symbols and cases, provide the ability to program as in
any other language. The four main constructs are named: section, universal,
class, and persistent. These are the overall constructs that allow for creation
of programs. Sections consist of universals, classes, and persistents.
Universals are methods (i.e. functions, procedures, subprograms). Classes, as
in other languages, are data structures that allow for the combining of data
and the methods that operate on that data. Classes consist of methods and
fields. The class methods and fields are essentially the same as universals and
persistents respectively. Persistents are most similar to global variables in
most other languages; however their data persists from run-time to run-time
such that the data retains its value until changed or the entire process is
destroyed.
Methods
(whether class methods or universals) consist of the remaining 15 constructs.
The basic nine constructs are: simple, constant, match, persistent, instance,
get, set, local, and evaluate. These
constructs provide for the main program execution and are at the heart of
Prograph. All of these constructs have
some combination of terminals and roots. Not all constructs have both or
either, and a construct could have an arbitrary number of roots and/or
terminals. For example the + primitive has two terminals and one root (i.e. two
inputs and one output). Methods also
have cases. All methods end with either a success, failure, or error message.
These messages provide the control logic for the constructs and make the cases
possible.
Cases are similar to the 'if-then-else' construct, and
variations thereof, found in most languages. When a method is initially called
the first case is run, if, during the course of the first case, a “next-case” control is found and
applied then the second case of the method will be run. The second case is
called with the exact same inputs as the previous case. If no second case
exists, a run-time error is thrown. This is applicably recursive, in that the
second case will call the third case and so on.
Figure 4 – An iterative factorial program
Within a case of a method
the nine basic constructs in conjunction with the control operators provide the
framework for programming. A simple construct, denoted by the rounded corner
rectangle, is simply a call to another method. There are five additional
graphical annotations to a simple, not including control symbols, which reveal
additional information about the method call. A bar under the method name
indicates that the method call is to a primitive. A bar over the method name
indicates that it is to an external method call (i.e. from a DLL, or external
program of some sort). A single slash before the method name indicates that the
method is a class method and Prograph will determine the proper method to call
from the instance that is required as the leftmost root. A double slash before
the method name indicates that the method is context-determined thus, for
instance, the method might be another method within the same class. Also an up
arrow next to the simple indicates that it is a call to a class method of its
parent class (i.e. super).
A
Constant construct, denoted by the constant value with a bar and a root
underneath, allow for constants as in other languages. A Constant value can be
any valid value and will be automatically typed.
A
Match construct, denoted by a terminal and bar over a constant value and nearly
always with a control construct to the right, allow for if statements. A match
will attempt to see if the data input is the same as the constant supplied.
Depending on the control operation associated with the match, they may do as
the control indicates (controls will be discussed in further detail later in
this discussion).
Persistent
constructs access the value of the persistent (i.e. global values). It has at
most one terminal and one root, to allow for both reading and writing to the
persistent.
Instance
constructs create an instance of the class. It has one terminal and one root.
If no values flow into the terminal then the class is initialized with no
parameters, however the permission of the terminal indicates that class
constructors can take inputs.
Get
and Set constructs allow for reading and writing of class attributes. Both
constructs take in an instance into its terminal, and an instance out of its
root. The Get has an additional root to provide for the data requested, and the
Set has an additional terminal to provide for the storage of the requested data
in the requested attribute.
Local
constructs allow for grouping of a section of code into a single graphical
element. This provides for a better view of the program as Locals allow for
better space management of the development environment, which is identical to
the expensive silicon real estate in circuit design.
The
Evaluate construct provides mathematical expressions into the language. An
Evaluate has one root, and as many terminals as desired. The expression uses
the alphabet (case insensitive ‘a’ to ‘z’ only) as designations for
terminals within the expression. For example the expression “a/b+c” would have three
terminals, starting on the left with a, then b in the middle, and c on the
right. The Evaluate will have as many terminals as letters used, however
letters must be used in alphabetical order (i.e. using the letter x will
automatically make 24 terminals to the Evaluate construct). The expression may
contain the following mathematical operations: @ (exponentiation), + (binary
and unary addition), - (binary and unary subtraction), * (multiplication), /
(floating point division), // (integer division), % (remainder from integer
division), & (bitwise AND), | (bitwise OR), ^ (bitwise XOR), ~ (unary
bitwise NOT), << (bit shift left), and >> (bit shift right).
The
External constructs simply allow the Simple, Constant, Match, Persistent, Get,
and Set to reference external data stored in a DLL, etc. In addition to these
there is also an External Address construct that takes an external structure as
input and returns a pointer to that structure. The External Persistent is
called External Global to point out the differences between a Prograph
Persistent and the idea of Global variables in other languages.
The
Controls in Prograph allow for change of the control flow based on how
constructs terminate. The most common use of controls is on a Match construct.
The logic for the control is denoted by a check or an x beside the construct.
Also a control will dictate what course of action should be taken upon a
successful check: Next Case, Terminate, Finish, Continue, and Fail. The check
indicates that it is true, while the x indicates it is not true. For
example say we have a Match named “STRING” with a check next to the name. If the input into
the Match is also “STRING”
then it would do the appropriate action dictated by the control (i.e. Fail,
Continue, etc). The control action directs the program execution. The Next Case
action will cause the method to execute the next case with its current inputs
and is depicted with a rounded box around the check or x. The Terminate action
will cause the method to immediately end execution with a successful result and
is depicted with rounded box and a bar above the check or x. The Finish action
will cause the method to complete the current case then immediately end
execution with a successful result and is depicted with a rounded box and a bar
below the check or x. The Fail action will halt the current method and send a fail
signal to the calling method and is depicted with a circle around the check or
x. The Continue action will cause execution to continue in the current case and
is depicted with a rounded box and a bar above and a bar below the check or x.
In
addition to the aforementioned constructs, individual constructs can be
connected by a Datalink and/or a Syncro link. A Datalink connects a root and a
terminal depicting flow of information. It is this depiction and functionality
that make Prograph a functional language. A Syncro link directionally connects
two constructs guaranteeing that start node will execute before the end node.
Since any construct could execute at any time (and is chosen randomly at design
time), the Syncro link provides a way to have the traditional imperative
execution to the degree chosen by the developer.

Other constructs not explained here include (but are not
limited to): Repeat annotations (construct is repeated until a fail, terminate,
or finish signal is sent), List annotation (construct will apply itself to
every member of the list), Loop annotations (construct is repetitively called
with the outputs sent as inputs to the next iteration), Partition annotations
(splitting a list based on Boolean criteria), and the Inject control (allowing
for the name of the operation to be supplied at run-time).
Types
In
Prograph there exist the following types: boolean, integer, list, none, null,
point, real, rectangle, rgb, string, and undefined. Boolean values are denoted
and displayed as TRUE or FALSE (case sensitive). Integers consist of
traditional signed integers (2^32), a number of any base (i.e. a binary number
2#10010101), and a 1, 2, or 4 byte ASCII character sequence. A list is
identical to a list in scheme or lisp with a limited number of elements (2^16 - 1 in the interpreter, and
2^32 -1 in the complier). The none type is used by Prograph to depict a type
when a terminal is not connected to a datalink. The Null type indicates no
value on a root or a class attribute. The point type is two integers enclosed
by curly brackets (“{}”)
and separated by a space; it represents the coordinates for a two dimensional
point in space. Reals are the same as traditional real numbers allowing for
values from -1.1E+4932 to +1.1E+4932. A Rectangle type depicts the coordinates
for two points defining the upper left and lower right corners of a rectangle;
this type is like a point but with four values instead of two. The RBG type
indicates a color denoted by the red blue and green values that compose it; this
is similar to a point but with three values. A string in Prograph consists of
any sequence of typeable characters limited in length to the same constraints
of the list type. Finally the undefined type is another internal type used by
Prograph when an operation/construct is skipped during execution.
Types
may be specified on roots and terminals, but are not required. In addition to
the aforementioned types, the specified type may also be: pointer, direct, a
class name, a list of types, or “<<>>” (which indicates that the type must be of
the same class the method is in). For more exact specifics on type definitions
see the BNF of the data types in the appendices.
Conclusion
Like
all languages, Prograph has its positive and negative aspects. It provides an easy
way to depict programs following a flow model, and the translation from flow
chart to code is very simple, as code is just as graphical as the flow chart.
One of the biggest disadvantages of all visual languages is the longer than
normal learning curve that a programmer must go through before becoming
proficient in the language. Also to Prograph specifically, it is a dead
language in that it is not widely used and as a language is not being
developed. However Prograph, with other visual languages, provide for a new
dimension to traditional programming not found elsewhere.
Appendix
A: Type BNF
<simple
value> ::= <delimited value> |
<default string>
<string> ::= <quoted string> | <atomic
string> | <default string>
<default
string> ::= any string which is not a
<delimited value>
<delimited value> ::= <quoted string> | <atomic
string> | <integer> | <real> | <boolean> | <null> |
<undefined> | <none>| <list> | <simple ext>
<atomic string> ::= any <atom> other than FALSE, TRUE,
NULL, UNDEFINED, or NONE
<boolean> ::= FALSE | TRUE
<null> ::= NULL
<undefined> ::= UNDEFINED
<none> ::= NONE
<list> ::= (<value*>)
<value*> ::= <delimited value>
<space><value*> | <delimited value> | <empty>
<simple
ext>::= <point> | <rectangle> | <RGB>
<point> ::= {<integer> <space> <integer>}
<rectangle> ::= {<integer> <space>
<integer> <space> <integer> <space> <integer>}
<RGB> ::= {<integer> <space>
<integer> <space> <integer>}
<space> ::= any nonempty string of characters whose
ASCII values are less than or equal to that of blank
<quoted
string> ::= <no
double>"<quoted string> | "<no double>"
<no
double> ::= any string of
characters, except "
<atom> ::= <letter atom> |
<special atom>
<letter
atom> ::= <letter>
<alphanumeric> | <letter>
<special atom> ::= any nonempty string of characters
having ASCII values greater than that of blank except those included in
<alphanumeric>
<integer> ::= <sign> <unsigned
integer>
<unsigned
integer> ::= <decimal integer> |
<based integer> | <ascii integer>
<decimal
integer> ::= <digit> <spaced
digits>
<spaced
digits> ::= <digit> <spaced
digits> | _<spaced digits> | <empty>
<based
integer> ::=
<digit+>#<alphanumeric>
<alphanumeric> ::= <letter> <alphanumeric> |
<digit> <alphanumeric>| <letter> | <digit>
<letter> ::= a | b | c | d | e | f | g | h | i
| j | k | l |m | n | o | p | q | r | s | t | u | v | w | x | y | z | A | B | C
| D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W
| X | Y | Z | _
<ascii
integer> ::= '<no single>' |
'<no single><no single>' |
'<no
single><no single><no single><no single>'
<no single> ::= any string of characters having ASCII
values greater than that of blank, except ' | ' '
<real> ::= <sign> <mantissa>
<exponent>
<mantissa> ::= <digit+> |
<digit+>.<digit*> | <digit*>.<digit+>
<exponent> ::= <sign> <digit+> |
E<sign> <digit+> | <empty>
<sign> ::= - | - | <empty>
<digit*> ::= <digit+> | <empty>
<digit+> ::= <digit> <digit*>
<digit> ::= 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
<empty> ::= the empty string
Appendix B: Primitives by Category
Bit
bit-and bit-not bit-or
bit-shift-l bit-shift-r bit-xor
test-all? test-bit? test-one?
Callbacks
dispose-method-pointer make-method-pointer
COM
COM-create-object COM-dispose-object
Data
copy get-resource-info get-resource-list
get-string-resource inst-to-list list-to-inst
shallow copy
File
close create delete
file-size get-file get-position
open put-file read
read-line rename resource-file
set-position write write-line
Graphics
find-bounds ints-to-point ints-to-rect
ints-to-rgb point-to-ints points-to-rect
rect-to-ints rect-to-points rgb-to-ints
Input/Output
accept answer answer-v
ask display
print-text
select set-dialog-font show
Interpreter control
abort abort-callback
compiled? debug
call execute
find-method halt
lookup-external-constant open-info-window
open-method-window switch-to-prograph
trace yield-cpu
Lists
(in) (join) (length)
attach-l attach-r detach-l
detach-nth detach-r find-instance
find-sorted get-nth insert-nth
make-list pack reverse
set-nth set-nth!
sort
split-nth unpack
Load & Save/Data Clustering
clear-bytes-map cluster-dispose cluster-new
cluster-size from-bytes load
save set-undefined-class
to-bytes
Logical
< <= =
> >= and
choose not or
switch xor ~=
Math
* **
+
++ +1
-
-- -1
abs
acos annuity asin
atan atan2 compound
cos div exp
idiv ln log10
max min
pi
power rand round
round-down round-up set-seed
sign sign-extend sin
sqrt tan trunc
Memory
address-to-object block-address block-size
compact-memory dispose-pointer from-handle
from-pointer get-cstring get-external-size
get-integer get-point get-process-refcon
get-real get-rect get-string
get-text heap-size lock-block
lock-string make-direct make-handle
make-pointer memory-callback new-block
object-to-address put-cstring put-integer
put-point put-real put-rect
put-string put-text set-process-refcon
string-address to-handle to-pointer
unlock-block unlock-string valid-heap?
String
format byte-length from-ascii
from-string ‘inÓ integer-to-string
‘joinÓ ‘lengthÓ middle
munge-string prefix string-length
string-to-integer suffix to-ascii
to-string tokenize
System
ancestors attr-com attributes
called-from-get called-from-meth called-from-set
calls-to-get calls-to-meth calls-to-set
children class-com class-section
classes create-class create-method
descendants editor-methods meth-com
meth-com-g meth-com-s meth-io-com
meth-io-com-g meth-io-com-s method-arity
method-classes method-section methods
pers-com persistent-section persistents
section-com section-contents sections
set-attr-com set-class-com set-meth-com
set-meth-com-g set-meth-com-s set-pers-com
set-section-com
Type
boolean? instance? integer?
list? external-type number?
real? string? type
Win32
get-application-instances get-application-main-window
get-command-line MakeIntResource
set-application-window
Appendix C: Optimus Prime
As part of this project
we wrote code in Prograph to implement the Sieve of Eratosthenes. This took
quite a bit of work as learning Prograph was not as easy as learning new
syntax, but it was an entirely different way of programming. The following
image shows the entire program:

This code will be made available along with the freeware Prolog Windows Interpreter on our website at http://students.cs.byu.edu/~dheise/cs330. The code is run by executing the method “start_Loop”. This will prompt the user for a number and then, using the algorithm, compute all the prime numbers smaller than the given number. One draw back of the freeware interpreter is the limited number of ways to show information to the user. The show primitive has a limited number of lines available to the user and going beyond this limit is possible, but futile since the user cannot see that information. Therefore, although the algorithm correctly computes the information, the user can only see a limited number of results using the show primitive.
Bibliography
[1] Cox, P.T. and I.J Mulligan "Compiling the Graphical Functional Language PROGRAPH" 1985.
[2] Cox, P.T. and Tomasz Pietrzykowski "Advance Programming in PROGRAPH" 1985.
[3] Steinman, Scott and Kevin Carver "Visual Programming with Prograph CPX" Manning Publications Co. 3, 1995