Prograph: A Visual Programming Language - CiteSeerX

18
Prograph: A Visual Programming Language David Heise & Tomas Joyner [email protected] [email protected] EECS 330: Introduction to Programming Languages Fall 2004

Transcript of Prograph: A Visual Programming Language - CiteSeerX

Prograph: A Visual Programming Language

David Heise & Tomas Joyner

[email protected] [email protected]

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).

Figure 1 – A Simple “Hello World” Program in Prograph

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.

Figure 2 – Classes and Inheritance. Classes a through e are depicted and inheritance is shown bottom to top (i.e. class e inherits from class c which inherits from class a)

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.

Figure 3 – Some Prograph Constructs

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

otations (splitting a list based on Boolean criteria), and the Inject

control (allowing for the name of the operation to be supplied at run-time).

Figure 5 – Syncro Links; a will run before both b and

c; both b and c will run before d, but no guarantee

about the order of execution for b and c

the next iteration), Partition ann

ypesT

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

orem

onclusion

af entioned 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.

C

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