http://software.intel.com/en-u
There is a relatively long intro discussion of about 8 minutes, and then we get into the nitty gritty of ParaSail.
This blog will follow the trials and tribulations of designing a new programming language designed to allow productive development of parallel, high-integrity (safety-critical, high-security) software systems. The language is tentatively named "ParaSail" for Parallel, Specification and Implementation Language.
interface Binary_Tree<Element_Type is Assignable<>> is var Left, Right : optional Binary_Tree; var Contents : Element_Type; end interface Binary_Tree;
var Copy_Of_Tree : optional Binary_Tree := Original_Tree;
Original_Tree.Left := Copy_Of_Tree;
Original_Tree.Left := Original_Tree;I'm not sure whether what we just did was of any use, but it does give you a feel for the power of expandable objects. The user doesn't have to write explicitly any deep copy operation, since from ParaSail's point of view, these are just subobjects, and ":=" assigns the whole thing, including all of the subobjects.
Original_Tree := Original_Tree.Left;This wipes out the old contents of Original _Tree and replaces it with a copy of its left subtree. But there seems to be some unnecessary copying going on here. The underlying sequence is:
Original_Tree := (Original_Tree.Left ::= null);
X := A[(I :+= 1)];
abstract interface Countable<> is op "+"(Left : Countable; Right : Univ_Integer) -> Countable; op "+"(Left : Univ_Integer; Right : Countable) -> Countable; op "-"(Left : Countable; Right : Univ_Integer) -> Countable; op "-"(Left, Right : Countable) -> Univ_Integer; op "=?"(Left, Right : Countable) -> Ordering; end interface Countable;This interface is used when defining a "countable interval" such as "X .. Y" where you want to be able to iterate from X up to Y, even though X and Y are not themselves of an integer type. For example, if X and Y are characters, it makes sense to define an interval such as 'a' .. 'z' and there is a desire to be able to go from 'a' to the next character in the interval, so by using the "+" operator from Countable that is easy to do. Just add 1. Similarly, we can iterate through the interval in reverse by subtracting 1. Or we can find out how big is the interval X..Y by computing (Y - X) + 1, where we are using the second "-" operator.
interface Countable_Set<Element_Type is Countable<>> is
op ".."(Left, Right : Element_Type) -> Countable_Set;
op "|"(Left, Right : Countable_Set) -> Countable_Set;
op "in"(Left : Element_Type; Right : Countable_Set) -> Boolean;
func Count(CS : Countable_Set) -> Univ_Integer;
...
end interface Countable_Set;
Implementing the Count function clearly will need to make use of the "+" or "-" Countable operations. But this now brings us to the question, is Integer itself a Countable type? Can we legally write Countable_Set<Integer>? Well if we look at the binary "+" and "-" operators for Integer we see:interface Integer<...> is
op "+"(Left, Right : Integer) -> Integer;
op "-"(Left, Right : Integer) -> Integer;
...
end interface Integer;
These don't actually match the operators expected for a Countable type. And if we were to simply add the missing operators, we would create significant ambiguity, since "X + 1" could either resolve to the existing Integer,Integer->Integer "+" or to the added Countable one, Integer,Univ_Integer->Integer "+". Not ideal. interface Integer<...> is op "+"(Left, Right : Integer) -> Integer; op "-"(Left, Right : Integer) -> Integer; ... implements for Countable op "+"(Left : Integer; Right : Univ_Integer) -> Integer; op "+"(Left : Univ_Integer; Right : Integer) -> Integer; op "-"(Left : Integer; Right : Univ_Integer) -> Integer; op "-"(Left, Right : Integer) -> Univ_Integer; end interface Integer;You can also omit the "for Countable" part and then the operations are available to implement any other module's interface. But the key thing is that you cannot call these operations directly on an Integer type. You can only invoke them when "viewing" an Integer as a "Countable" object. You can have multiple sections after "implements" each section starting with "for Interface1, Interface2, ..." if there are several different sets of operations that need to be implemented to satisfy the needs for different sets of interfaces. In general situations like this are expected to be rare, but when you bump into one, it is useful to have a way to avoid the ambiguity and still satisfy the needs of the other interface.
ref X => M[I]; ref const R => T.Right; ref var L => T.Left;
class Tree_Iterator is
ref Current_Node : Tree_Node;
var Enclosing_Node : optional Tree_Iterator;
var Which_Child : Child_Index;
exports
func First_Item(ref Root : Tree_Node) -> Tree_Iterator is
// Return leftmost child of Root to start the iteration
return Leftmost_Child
((Current_Node => Root, Enclosing_Node => null, Which_Child => 0));
end func First_Item;
func Leftmost_Child(It : Tree_Iterator) -> Tree_Iterator is
// Return iterator designating leftmost child
if Num_Children(It.Current_Node) == 0 then
// We are at the leftmost child already
return It;
else
// Recurse down the left side
return
(Current_Node => It.Current_Node[1],
Enclosing_Node => It,
Which_Child => 1);
end if;
end func Leftmost_Child;
func Next_Item(It : Tree_Iterator) -> optional Tree_Iterator is
// Advance iterator to next item in left-to-right depth-first walk
if It.Enclosing_Node is null then
// All done
return null;
elsif It.Which_Child < Num_Children(It.Enclosing_Node.Current_Node) then
// Return next child of same enclosing node
return Leftmost_Child
((Current_Node => It.Enclosing_Node[It.Which_Child + 1],
Enclosing_Node => It.Enclosing_Node,
Which_Child => It.Which_Child + 1));
else
// Recurse to go to next sibling of enclosing node
return Next_Item(It.Enclosing_Node);
end if;
end func Next_Item;
...
end class Tree_Iterator;
operation_input ::=
id ':' type [ := default ]
| 'var' id ':' type
| 'ref' [ 'var' | 'const' ] id ':' type
| 'global' [ 'var' ] id ':' type
| [ 'locked' | 'queued' ] [ 'var' ] id ':' type
operation_output ::=
[ id ':' ] type
| 'ref' [ 'var' | 'const' ] [ id ':' ] type
func Append(var L : List; E : Element);
op "indexing"(ref V : Vector; I : Index) -> ref Element;
func Get_Next(queued var Q : Queue) -> Element;
We will be posting a new draft of the ParaSail reference manual reflecting these changes shortly to the ParaSail google group:func GCD(X, Y : Integer) -> Integer is case X =? Y of [#less] => return GCD(X, Y mod X); [#equal] => return X; [#greater] => return GCD(X mod Y, Y); end case; end func GCD; func Print(F : ref var File; X : Integer) is if abs X >= 10 then Print(F, X/10); end if; Print(F, '0' + (X rem 10)) end func Print; func "|"(X : Set; E : Elem) -> Set is return Union(X, Make_Set(E)); end func "|";
for X => Root while X not null loop case X.Kind of [#leaf] => Process(X.Data); [#unary] => Process(X.Data); || continue loop with X => X.Operand; [#binary] => Process(X.Data); || continue loop with X => X.Left; || continue loop with X => X.Right; end case; end loop;Here is an example using exit loop:
const Result : Id_Type; for X => Root then X.Left || X.Right while X not null concurrent loop if X.Value == Desired_Value then exit loop with Result => X.Id; end if; end loop with Result => null;This first example processes an expression tree, and creates parallelism by using an explicit continue loop statement in concert with a concurrent sequence ("||") construct. The second example searches a binary tree and creates parallelism by both the use of concurrent loop and by having two values in the then part of the for loop header, which will result in the execution of the loop splitting into two separate threads at each binary node.