Back to my main page
The ProcessJ Language
ProcessJ (Java-style Occam) is a brand new language which
fuses two very important features from two existing
programming languages: The process orientated design
methodology (including channels, barriers, mobile
processes etc.) from occam [] and the well known syntax
of Java [].
The reason for the development of ProcessJ is mainly to
try to push process oriented development. We believe
that process orientation is the best way to program fine
grained parallelism; especially when dealing with
multi-core architectures, which are becoming
increasingly popular.
The design of ProcessJ follows the following simple
thesis: Attempt to provide the functionality of occam-pi
but use a Java style (i.e., 100% match java if possible,
else adopt the Java style for new constructs).
With the popularity of multi-core architectures this
naturally remains a target for a process oriented
language like ProcessJ, but in addition, we intend to
provide multiple back-ends to the compiler; in
particular, we are working on a C with MPI code
generator, which lets your take advantage of process
oriented design principles and language features as well
as a distributed runtime environment. Other targets that
are planned include java bytecode for portability
reasons.
Please check back regularly as we will be updating this
page as we progress. This work is supported by the UNLV
Research Development Award 2008.
1 ProcessJ Examples
Although the development of ProcessJ is still in its early
stages, the syntax is more or less determined. Here is
an example of a piece of occam code with an ALT and an
extended rendez-vous:
PROC foo(CHAN OF INT in1?,
CHAN OF INT in2?, CHAN OF INT out!)
SEQ
ALT
INT y:
in1 ? y
out ! y
INT y:
in2 ? y
out ! y
INT y:
in1 ?? y
out ! y
:
which in ProcessJ would look like this:
proc void foo(chan<int>.read in1,
chan<int>.read in2,
chan<int>.write out) {
int y;
alt {
y = in1.read() : {
out.write(y);
}
y = in2.read() : {
out.write(y);
}
}
y = in1.read({ out.write(y); });
}
The ProcessJ code is much closer to the well-known Java
syntax, and in addition to having { } constructs, the
keywords are no longer set in capitals, and indentation
no longer matters.
We believe that this will prove to be a good motivator
for learning process oriented design and programming.
2 The building blocks of ProcessJ
2.1 Data Types
In the spirit of keeping ProcessJ close to Java with
respect to syntax, we have chosed to use the Java atomic
type system, rather than that of occam.
2.1.1 Atomic Types
In Java, the atomic types are: boolean, byte, short,
char, int, float, long, double. ProcessJ uses the same names, but in addition,
string is an atomic type (ProcessJ does not have
the notion of objects, and since Java implements strings
as an object, this seemed necessary).
In addition to the regular atomic types, ProcessJ has
an additional number (currently 2) of atomic types
inherited from occam. The first is a timer
type, which in reality is the reading end of a timing
process that is always willing to engage in
communication. The second is a barrier type,
which is a special construct that defines a full
barrier. Processes enrolled (using the keyword
enroll, which can be prefixed by a par
or a for-loop, if needed) on a barrier can
synchronize on it by using the sync
keyword.
2.1.2 Type constructors
Java has but two type constructors, namely classes
and arrays. Since ProcessJ is not object oriented we do
not have the notion of classes or objects, but we do
have arrays; arrays in ProcessJ look and behave similarly
to their Java cousins. Only a few differences exist:
- The syntax for declaring a ProcessJ array requires
the [..] to be placed on the type and not on
the name of the variable/parameter.
- Empty dimensions are allowed only on parameters or
on variables if assigned an array value whose
dimensions can be determined at compile time.
- Java only allows for array constants at variable
declaration time. ProcessJ treats array constants like
any other constant.
- A number of useful array operations like
size must be made available; we haven't
determined if a size of an array should be accessed
as
s = array.size
or as
s = size(array)
At the moment the first one is
favoured.
- occam implements array slicing, we have not yet
determined if we are going to support this in ProcessJ.
Eecordsare not found in Java (Records can be
implemented as classes without any methods), but since
we do not have classes in ProcessJ, it is necessary to
have at least records available. An example of a record
ld be:
type record myRecord {
int a;
double d;
}
Like arrays, records
constant values. An example of a constant value of the
above record could be
myRecord{4, 5.7}
An additional two type constructors exist, namely
protocol and process types. A protocol determines which
types a channel can carry; We have not determined the
exact syntax for protocols as of yet. a process type,
or a proc type looks like this:
type proc is (.....);
where ..... is a list of formal parameters of a
process definition. A process definition is needed when
implementing mobile processes, not only for specifying
that a mobile process' declarations 'implements' this
process type, but also for specifying the type that
travels across the channels that will carry the mobile
when it is in its suspended state (i.e., not
executing).
Room for discussion: arrays are not declared
using the type word array, whereas records are.
2.2 Declarations
2.2.1 Constants
In Java the concept 'constant' does not exist
explicitly; instead, a final field cannot be assigned
to, so in effect, it behaves like a constant; However,
it is not possible to declare local constants within a method.
In occam a constant is prefixed the keyword VAL; VAL
constants can be local as well as parameters.
In ProcessJ we have decided to call a spade a spade
and simply use the word const. Constants can
be declared at the top level, along with the type
declarations; as well as be formal parameters, and
local. If a constant is defined locally or globally it
must be intialized at declaration time:
const int WORKING_TIME = 100000;
whereas when used as a formal we could have:
proc void foo(const int i) { ... }
2.2.2 Local and Parameters
A local or a parameter in ProcessJ is declared in the
exact same was as in Java:
[<modifiers>] <type> [<array_dims>] name [ = initializer]
where currently the only two modifiers we have are
const, used for declaring a constant (which
then requires the initializer to be present), and
mobile used to declare the variable as holding
a mobile type.
2.2.3 Channel Declarations
Channels are a new concept not found in Java, but
plays an integral role in occam, and for that matter,
in any process oriented design. A channel carries
values of a certain type in one direction, from or or
more senders to one or more receivers (channels can be
one-to-one, one-to-many, many-to-one, or many-to-many).
If a channel is has many senders or many receivers (or
both) was say that it is shared. When declaring
channels we must declare which end of it is shared, and
also specify the type that it carries. For example:
shared write chan<Agent_message> report
declares a channel called report, which
carries values of the Agent_message type, and
is shared on the writing end (i.e., it can have
multiple writers. When a channel is declared shared, it
must be claimed by a process before it can be
written to/read from. (More about claim later)
In addtion, we have channel-end types and
expressions as well. A channel-end type is simply a
channel type followed by a .read or a
.write, indicating which end of a channel type
we are interested in. Likewise, if a variable contains
a whole channel, and not just a channel-end,
.read and .write can be specified. If
a read() operation is applied to a whole
channel, the read end is automatically picked. The same
holds for the write() operation.
2.3 Statements
In the tradition of keeping the syntax as close to
Java as possible, the majority of statements in ProcessJ
have the same syntactical structure as statements in Java.
- Assignment
Java alows assignment like a = b = c =
6;, and occam allows assignments like a,b,c
= 7,5,d. Either type can cause aliasing
problems, but at the moment ProcessJ only supports a
single assignment per =, though we will
probably end up supporting both types of assignment,
but not a mixture (That would probably not be
syntactically viable anyhow!).
- Choice
ProcessJ will support Java-style if statements, both
with and without an else clause. Whether a ternary
exspression will be supported has not yet been
determined. We might introduce an elseif keyword, but
that is only a thought at the moment.
Java-style switch/case statements will be implemented
in ProcessJ, and in addition we might implement the
case statement of occam that allows to switch on a
channel read. The extension to Java's switch
statement then would require that the case labels can
be not only integral constants, but also union constants.
- Repetition
Java currently has standard for,
do, and while loops, in addition to
iterators. ProcessJ will implement do and
while loops according to the standard Java
syntax; for loops are a little more
difficult as the occam equivalent is somewhat
different in that a for loop can be prefixed
with the par construct, allowing for the
body of the loop to be done in parallel. This would
ultimately require some analysis of the body of the
loop, or a pre execution of the loop to determine the
index set. This is only possible if the body of the
loop cannot change the variables that are used in the
loop condition. Since we do not allow global
variables, and use a call-by-value call semantics, it
should be reasonbly simple analyze the assignments of
the body to assure that if the loop is to be executed
in parallel no loop variables may be re-assigned. An
example of how to do this has been provided by Neil
Brown and works as follows:
par for (i=,j=0;i<100;i+=2,j=j+2*i)
statements
would require the index set
(i,j) = [(0,0), (2,4), (4,12) ...]
to be pre-computed, and then the statements executed
in parallel over this index set.
As far as iterators, we have not made any decissions
at all.
Blocks and par
occam provides both a PAR and a SEQ
construct. Examples are:
SEQ
a := 5
b := 7
and
PAR
a := 5
b := 7
whe the assignments in the SEQ block are done
in sequence (i.e., sequentially), and the assignments
in the PAR block are done in parallel. In
ProcessJ there is no need for the SEQ
construct, as by default, everything is done
sequentially, so a simple Java block using { and } is
sufficient. In ProcessJ a block prefixed by the
par keyword will be a parallel block.
Communication
The notion of channel communication does not exist in
Java; this is 100% inherited from occam. Thus this
requires a brand new Java-like syntax. In occam
a channel can be read or written in the following
way:
in ? x
out ! x
The first statement reads a value from the
in channel into x and the second
writes the same value to the out
channel.
The suggested syntax for joccam is as follows:
x = in.read();
out.write(x);
Though ProcessJ does not have objects, we chose this
'method invocation' style to stay close to something
Java programmers know.
Extended rendez-vous in occam (a construct where the
writer/sender is not released from the synchronous
call until the code in the extended rendez-vous block
has been executed) look like this (If more than one
process must be executed in the rendez-vous block a
PAR or a SEQ block is needed):
in ?? x
SEQ
out ! x
out ! x
this, in ProcessJ, would look like this:
x = in.read({out.write(x); out.write(x);});
Alternatively the rendez-vous block could be prefixed
a par.
Barriers
A barrier in occam is an atomic typed, and also so in
ProcessJ. Barriers are declared, enrolled on,
synchronizes on and temporarily resigned from in he
following way:
barrier b;
...
enroll(b) {
};
...
sync(b);
...
resign(b) {
};
Alternatively a par can be placed infront of
the enroll statement. Barriers can also be passed as
parameters to function.
skip and stop
Both skip (which is a no-operations process),
and stop (which is a process that refuses to
engage in any action, thus deadlocking the process)
exist only in occam. Typically skip can be
replaced by a ; in Java, but both are
statements in ProcessJ.
Mobile invocation, suspension, and
resumption
The concept of mobiles does not
exist in Java, but is the latest extension to
occam-pi. There are two classes of mobiles: mobile
channels and mobile processes. For now we shall
restrict ProcessJ to have mobile processes, and we will
later return to the mobile channels (and mobile channel
bundles, as well as issues with arrays of mobile).
2.4 Expressions
Expressions in ProcessJ (except the addition of
channel reads and timer reads) are similar to Java
expression.
3 Modularity
For ProcessJ to be a proper language some sort of
modularity and import/include mechanism must be
provided. The Java package model is slightly
complicated to implement, and relies somewhat on the
object oriented aspects of the language. Occam uses an
include statement on a per file basis; something is
much easier to implement. For joccam we shall stick to
the occam way and simply include files as needed.
4 I/O
To come later
5 Java Call Backs
To come later
6 Multiple Back-ends
Currently we have a occam and a c with MPI back-end in the works.