Difference between revisions of "Tutorial - Simple Types"

From Mesham
Jump to navigationJump to search
Line 20: Line 20:
  
 
In the previous section we saw that, by default, element types such as [[Int|Ints]] have a default set of type behaviour associated with them. These types are combined together to form a chain. The type chain resulting from the use of an [[Int]] and these defaults is: [[Int]]::[[Onesided|onesided]]::[[Stack|stack]]::[[Allocated|allocated]][ [[Multiple|multiple]][] ]. There are a number of points to note about this chain, firstly the ''::'' operator (the type chaining operator) chains these independent types together and precedence is from right to left - so the behaviour of the types on the right override behaviour of those to the left of them if there is any conflict. For example if we were to append another form of memory allocation, the [[Heap|heap]] type which allocates memory on the heap, to rightmost end of the chain then this would override the behaviour of the [[Stack|stack]] type which would be to the left of it.
 
In the previous section we saw that, by default, element types such as [[Int|Ints]] have a default set of type behaviour associated with them. These types are combined together to form a chain. The type chain resulting from the use of an [[Int]] and these defaults is: [[Int]]::[[Onesided|onesided]]::[[Stack|stack]]::[[Allocated|allocated]][ [[Multiple|multiple]][] ]. There are a number of points to note about this chain, firstly the ''::'' operator (the type chaining operator) chains these independent types together and precedence is from right to left - so the behaviour of the types on the right override behaviour of those to the left of them if there is any conflict. For example if we were to append another form of memory allocation, the [[Heap|heap]] type which allocates memory on the heap, to rightmost end of the chain then this would override the behaviour of the [[Stack|stack]] type which would be to the left of it.
 +
 +
#include <io>
 +
#include <string>
 +
 +
function void main() {
 +
    var a:Int::stack::onesided::allocated[multiple[]];
 +
    a:=78;
 +
    print(itostring(a)+"\n");
 +
};
 +
 +
The above code is, in terms of runtime behaviour, absolutely identical to the first code example that we have seen - just we have explicitly specified the type of variable ''a'' to be the type chain that is inferred in the first example. As you can see, it just saves typing being able to write code without all these explicit types in many cases. It is also important to note that we can associated optional information with these types. For instance, we have provided the [[Multiple|multiple]] type as a parameter to the [[Allocated|allocated]] type. Parameters can be anything (further type chains, values or variables known at compile time) and in the absence of further information it is entirely optional to provide empty ''[]'' braces or not.
 +
 +
=== Let's go parallel ===
 +
 +
So the code we have seen up until this point isn't very exciting when it comes to parallelism. In the following code example we are involving two processes with shared memory communication:
 +
 +
#include <io>
 +
#include <string>
 +
 +
function void main() {
 +
    var a:Int::allocated[single[on[0]]];
 +
    proc 1 {
 +
      a:=78;
 +
    };
 +
    sync a;
 +
    proc 0 {
 +
      print("Value: "+itostring(a)+"\n");
 +
    };
 +
};
 +
 +
The important change here has been that we have modified the [[Multiple|multiple]] type to instead be the [[Single|single]] type with the [[On|on]] type provided as a parameter and then the value ''0'' to this type.

Revision as of 16:25, 14 January 2013

Introduction

In this tutorial we will be looking at a simple use of types in Mesham and how we can change what our code is doing just by modifying the type. It is assumed that the reader has already worked through the Hello world tutorial and is familiar with the concepts discussed there.

A question of types

#include <io>
#include <string>

function void main() {
   var a:=78;
   print(itostring(a)+"\n");
};

In the above code snippet we have included the appropriate system headers (for printing and integer to string conversion at line 6), specified our program entry point via the main function and declared variable a to contain the value 78. Whilst this looks very simple (and it is) there are some important type concepts lurking behind the scenes. There are three ways of declaring a variable - via explicit typing, by specifying a value as is the case here and the type will be deduced via inference or by specifying neither and postponing the typing until later on (such as in the Hello world tutorial as with variable p which was inferred to be an Int later on as it was used in a par statement.)

In the code above, via type inference, variable a is deduced to be of type Int and, in the absence of further types, there are a number of other default types associated with an integer; the stack type so specify that it is allocated to the stack frame of the current function, the onesided type which determines that it uses one sided (variable sharing) communication, the allocated type that specifies memory is allocated and lastly the multiple type that specifies that the variable is allocated to all processes. So, by specifying a value the language has deduced, via inference all this behaviour which can be overridden by explicitly using types. Note that these defaults are not just for Ints, they actually apply to all element types.

Type chains

In the previous section we saw that, by default, element types such as Ints have a default set of type behaviour associated with them. These types are combined together to form a chain. The type chain resulting from the use of an Int and these defaults is: Int::onesided::stack::allocated[ multiple[] ]. There are a number of points to note about this chain, firstly the :: operator (the type chaining operator) chains these independent types together and precedence is from right to left - so the behaviour of the types on the right override behaviour of those to the left of them if there is any conflict. For example if we were to append another form of memory allocation, the heap type which allocates memory on the heap, to rightmost end of the chain then this would override the behaviour of the stack type which would be to the left of it.

#include <io>
#include <string>

function void main() {
   var a:Int::stack::onesided::allocated[multiple[]];
   a:=78;
   print(itostring(a)+"\n");
};

The above code is, in terms of runtime behaviour, absolutely identical to the first code example that we have seen - just we have explicitly specified the type of variable a to be the type chain that is inferred in the first example. As you can see, it just saves typing being able to write code without all these explicit types in many cases. It is also important to note that we can associated optional information with these types. For instance, we have provided the multiple type as a parameter to the allocated type. Parameters can be anything (further type chains, values or variables known at compile time) and in the absence of further information it is entirely optional to provide empty [] braces or not.

Let's go parallel

So the code we have seen up until this point isn't very exciting when it comes to parallelism. In the following code example we are involving two processes with shared memory communication:

#include <io>
#include <string>

function void main() {
   var a:Int::allocated[single[on[0]]];
   proc 1 {
      a:=78;
   };
   sync a;
   proc 0 {
      print("Value: "+itostring(a)+"\n");
   };
};

The important change here has been that we have modified the multiple type to instead be the single type with the on type provided as a parameter and then the value 0 to this type.