/* This contains some example code in the ParaFlow langauge. * ParaFlow is syntactically related to C with some elements * of Python and a few new elements. Two of the most important * new elements are the 'para' constructs which enable parallel * execution, and the 'flow' type functions which are guaranteed * to be free of side effects. */ to printHello() // Simple no parameter or return result declaration { print("Hello world"); } to printWordLots(string word, int count) // Declaration with a couple of parameters, no return value. { for (i in 0 to count) prin(word + " "); // prin does not print a line break. print(""); } to factorial(int n) into (float result) // Declaration with an integer parameter that returns floating point result { result = 1; for (i in 2 to n+1) result *= i; } to stats3(float a, float b, float c) into (float sum, float average) // Declaration with three float inputs and two float outputs. { sum = a + b + c; average = sum/3; } to swap(var a,var b) into (var c,var d) // Declaration with two unspecifed parameters that returns two unspecified // results. System does type checking at run time when vars are used. // NB: currently var only partially implemented - mostly for print statement. { c = b; d = a; } flow reverseRange(int oldStart,int oldEnd,int seqSize) into (int newStart,int newEnd) // Flow function have no side effects. The compiler checks this. // Flow functions can read from anywhere, but can only write to // local variables and their output. Calls to "flow" functions are // allowed inside of para statements, while calls to "to" // functions are not. { newStart = seqSize - oldEnd; newEnd = seqSize - oldStart; } // The actual parallelism is done via the "para" construct. The // general form of this construct is: // para (element in collection) action expression // where collection is something like an array or dir, // element is a variable that refers to something in the // collection, and action is a key word such as 'do' 'get', 'add', 'max' // 'filter', etc. // Most para actions return a result. The following example // sums up all the elements in an array. int sum = para (i in a) + i; // This example creates a new array containing only the even numbers // in an larger array array of int evens = para (i in a) filter a%2 == 0; // This creates a table of sine values indexed by degrees, assuming that // the sin() math library function takes radians. In general the para // action get returns a collection of the same type and size as the // input collection. array of double sinLookup = para (i in 0 to 360) get math.sin(i*2*math.pi/360); // Other para actions include // multiply - returns the product of all expressions // min - returns the smallest expression // max - returns the largest // argmin - returns the index of the element that produced the smallest // expression. If the collection is an array then the index is of // type long, if the collection is a dir then the index is a string. // argmax - returns the index of the element producing largest expression. // The 'do' action does not produce a value. It can be used to change // the values of the items in the collection. A 'do' action is followed // by a statement rather than an expression. The statement can be // compound. Here's an example of a para statement that squares every member // of an array: array of int a = (1,2,3,4,5,6,7,8,9,10); para (i in a do) i = i*i; // Within a para do statement only the element, and any // local variables declared within the statement // may be modified. When the element is modified, the corresponding // value in the collection is updated. /* ParaFlow is object oriented, but not in your face about it. * It does not support multiple inheritance. It does support * interfaces. Built in types include: byte (8 bits), short (16 bits), * int (32 bits), long (64 bits), float (double-precision IEEE), * string (arbitrarily long), files, array, list (internally a doubly-linked list), * dir (internally a hash table), and tree (internally a self-balancing red-black tree). * Arrays, lists, and catalogs all implement the collection interface. * Anything that implements this interface can be used in para functions, * and for statements. */ class color // Simple classes are much like C structures. There is no // data hiding. If you want to hide data you access the object // through an interface, or anonymously. { byte r,g,b; } class usaAddress { string street; // May include more than one line and apartment number string city,state; float zipCode; // The extended zip code is stored to the right of decimal } class point /* A point in 2-D space. */ { double x,y; } class circle /* A circle. */ { point center; double radius; flow diameter() into (double result) { result = 2 * 3.14 * self.radius; // Instance variables are accessed via "self" } flow area() into (double result) { result = 3.14 * self.radius * self.radius; } } class hash implements collection // Here we implement a hash table, which can be used as a collection. // NB - there are many things about this not yet implemented... { class element // This is an element in our hash list // Note that objects can have objects defined inside of themselves. { string name; var value; // Variable type } // Just a fixed size array of lists. This will contain elements. array[1024] of list of element buckets; // NB list isn't working at the moment either. flow func(string name) into (int result) // We use a simple but effective hash function, since 5 is coprime to 1024 { result = 0 for (c in name) { result *= 5; result += c; } result %= buckets.size; } to add(string name, class val) // Create new element based on name and val, and add to hash. { el = element.create; el.name = name; el.value = val; buckets[func(name)].add(el); } flow find(string name) into (class val) // Find element { for (el in buckets[func(name)]) { if (el.name == name) { val = el.value; break; } } } to mustFind(string name) into (class val) throws errNotFound // Find element or throw exception // (NB currently exceptions and throws are not implemented) { val = find(name); if (!val) punt(errNotFound(name)); } class hashIterator implements iterator // The iterator object for a hash has to maintain a little // internal state. { hash h // A reference to our hash int bucketIx // Which list we are currently on iterator listIterator // Iterator for the list to create(hash h) // We need a more complex initialization than all zeroes, // so we have to have a create method // (NB create vs. new, vs just having a factory function of // your own choosing not decided yet.) { self.h=h self.bucketIx=0 self.listIterator = buckets[bucketIx] } to advance() into (var object) // The advance method is all that's required to be // an iterator. It just returns the next object, // or nil when nothing is left. { loop { object = self.listIterator.advance(); if (object) break self.bucketIx += 1; if (self.bucketIx >= self.h.buckets.size) break; } } } to iterate into (iterator) // The iterate method is all that's required to be a collection. // This just returns an object with an iterator interface. { iterator = hashIterator.create(self); } } // End of hash object class countingHash extends hash // Here we extend the hash by keeping track of how many elements // are in it. { int count; to add(string name, class val) { self.count += 1; parent.add(name, val); } } // Instead of the problematic C/Java switch statement there is a case // statement that is as so: string message; case (errCode) { 0 : ; // leave message nil 1 : message = "File not found"; 2 : message = "Write protected"; 3,4 : message = "Privacy violation"; 18 : {message = "Hull breech"; alarm("evacuation")} else : message = "Error code #" + errCode; } if (message) punt(message); Only a single statement is allowed after each label. A comma-separated list of labels can share the same statement. Multiple statements enclosed in braces are considered a single statment. // Related to case maybe have a cond expression. string message = cond (errCode) { 0: nil, 1: "File not found", 2: "Write protected", 3,4: "Privacy violation", 18: "Hull breech", default: message = "Error code #" + errCode; } // or maybe instead string message = cond ( errCode == 0 : nil, errCode == 1 : "File not found", 2 < errCode && errCode < 12 : "System errCode " + errCode, errCode == 18: "Hull breech", default : "Error code #" + errcode )