mirror of
https://github.com/adambard/learnxinyminutes-docs.git
synced 2024-12-25 16:23:37 +03:00
[Chapel/en] Update chapel.html.markdown (#3877)
This commit is contained in:
parent
781ebf270b
commit
950adf2cc3
@ -13,7 +13,16 @@ as well as multi-kilocore supercomputers.
|
|||||||
|
|
||||||
More information and support can be found at the bottom of this document.
|
More information and support can be found at the bottom of this document.
|
||||||
|
|
||||||
|
You can refer to the official site for [latest version](https://chapel-lang.org/docs/master/primers/learnChapelInYMinutes.html) of this document.
|
||||||
|
|
||||||
```chapel
|
```chapel
|
||||||
|
/*
|
||||||
|
Learn Chapel in Y Minutes
|
||||||
|
|
||||||
|
This primer will go over basic syntax and concepts in Chapel.
|
||||||
|
Last sync with official page: Sun, 08 Mar 2020 08:05:53 +0000
|
||||||
|
*/
|
||||||
|
|
||||||
// Comments are C-family style
|
// Comments are C-family style
|
||||||
|
|
||||||
// one line comment
|
// one line comment
|
||||||
@ -21,34 +30,43 @@ More information and support can be found at the bottom of this document.
|
|||||||
multi-line comment
|
multi-line comment
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Basic printing
|
/*
|
||||||
|
Basic printing
|
||||||
|
*/
|
||||||
|
|
||||||
write("Hello, ");
|
write("Hello, ");
|
||||||
writeln("World!");
|
writeln("World!");
|
||||||
|
|
||||||
// write and writeln can take a list of things to print.
|
// ``write`` and ``writeln`` can take a list of things to print.
|
||||||
// Each thing is printed right next to the others, so include your spacing!
|
// Each thing is printed right next to the others, so include your spacing!
|
||||||
writeln("There are ", 3, " commas (\",\") in this line of code");
|
writeln("There are ", 3, " commas (\",\") in this line of code");
|
||||||
|
|
||||||
// Different output channels:
|
// Different output channels:
|
||||||
|
use IO; // Required for accessing the alternative output channels
|
||||||
|
|
||||||
stdout.writeln("This goes to standard output, just like plain writeln() does");
|
stdout.writeln("This goes to standard output, just like plain writeln() does");
|
||||||
stderr.writeln("This goes to standard error");
|
stderr.writeln("This goes to standard error");
|
||||||
|
|
||||||
|
/*
|
||||||
|
Variables
|
||||||
|
*/
|
||||||
|
|
||||||
// Variables don't have to be explicitly typed as long as
|
// Variables don't have to be explicitly typed as long as
|
||||||
// the compiler can figure out the type that it will hold.
|
// the compiler can figure out the type that it will hold.
|
||||||
// 10 is an int, so myVar is implicitly an int
|
// 10 is an ``int``, so ``myVar`` is implicitly an ``int``
|
||||||
var myVar = 10;
|
var myVar = 10;
|
||||||
myVar = -10;
|
myVar = -10;
|
||||||
var mySecondVar = myVar;
|
var mySecondVar = myVar;
|
||||||
// var anError; would be a compile-time error.
|
// ``var anError;`` would be a compile-time error.
|
||||||
|
|
||||||
// We can (and should) explicitly type things.
|
// We can (and should) explicitly type things.
|
||||||
var myThirdVar: real;
|
var myThirdVar: real;
|
||||||
var myFourthVar: real = -1.234;
|
var myFourthVar: real = -1.234;
|
||||||
myThirdVar = myFourthVar;
|
myThirdVar = myFourthVar;
|
||||||
|
|
||||||
// Types
|
/*
|
||||||
|
Types
|
||||||
|
*/
|
||||||
|
|
||||||
// There are a number of basic types.
|
// There are a number of basic types.
|
||||||
var myInt: int = -1000; // Signed ints
|
var myInt: int = -1000; // Signed ints
|
||||||
@ -75,30 +93,34 @@ type RGBColor = 3*chroma; // Type representing a full color
|
|||||||
var black: RGBColor = (0,0,0);
|
var black: RGBColor = (0,0,0);
|
||||||
var white: RGBColor = (255, 255, 255);
|
var white: RGBColor = (255, 255, 255);
|
||||||
|
|
||||||
// Constants and Parameters
|
/*
|
||||||
|
Constants and Parameters
|
||||||
|
*/
|
||||||
|
|
||||||
// A const is a constant, and cannot be changed after set in runtime.
|
// A ``const`` is a constant, and cannot be changed after set in runtime.
|
||||||
const almostPi: real = 22.0/7.0;
|
const almostPi: real = 22.0/7.0;
|
||||||
|
|
||||||
// A param is a constant whose value must be known statically at
|
// A ``param`` is a constant whose value must be known statically at
|
||||||
// compile-time.
|
// compile-time.
|
||||||
param compileTimeConst: int = 16;
|
param compileTimeConst: int = 16;
|
||||||
|
|
||||||
// The config modifier allows values to be set at the command line.
|
// The ``config`` modifier allows values to be set at the command line.
|
||||||
// Set with --varCmdLineArg=Value or --varCmdLineArg Value at runtime.
|
// Set with ``--varCmdLineArg=Value`` or ``--varCmdLineArg Value`` at runtime.
|
||||||
config var varCmdLineArg: int = -123;
|
config var varCmdLineArg: int = -123;
|
||||||
config const constCmdLineArg: int = 777;
|
config const constCmdLineArg: int = 777;
|
||||||
|
|
||||||
// config param can be set at compile-time.
|
// ``config param`` can be set at compile-time.
|
||||||
// Set with --set paramCmdLineArg=value at compile-time.
|
// Set with ``--set paramCmdLineArg=value`` at compile-time.
|
||||||
config param paramCmdLineArg: bool = false;
|
config param paramCmdLineArg: bool = false;
|
||||||
writeln(varCmdLineArg, ", ", constCmdLineArg, ", ", paramCmdLineArg);
|
writeln(varCmdLineArg, ", ", constCmdLineArg, ", ", paramCmdLineArg);
|
||||||
|
|
||||||
// References
|
/*
|
||||||
|
References
|
||||||
|
*/
|
||||||
|
|
||||||
// ref operates much like a reference in C++. In Chapel, a ref cannot
|
// ``ref`` operates much like a reference in C++. In Chapel, a ``ref`` cannot
|
||||||
// be made to alias a variable other than the variable it is initialized with.
|
// be made to alias a variable other than the variable it is initialized with.
|
||||||
// Here, refToActual refers to actual.
|
// Here, ``refToActual`` refers to ``actual``.
|
||||||
var actual = 10;
|
var actual = 10;
|
||||||
ref refToActual = actual;
|
ref refToActual = actual;
|
||||||
writeln(actual, " == ", refToActual); // prints the same value
|
writeln(actual, " == ", refToActual); // prints the same value
|
||||||
@ -107,7 +129,9 @@ writeln(actual, " == ", refToActual); // prints the same value
|
|||||||
refToActual = 99999999; // modify what refToActual refers to (which is actual)
|
refToActual = 99999999; // modify what refToActual refers to (which is actual)
|
||||||
writeln(actual, " == ", refToActual); // prints the same value
|
writeln(actual, " == ", refToActual); // prints the same value
|
||||||
|
|
||||||
// Operators
|
/*
|
||||||
|
Operators
|
||||||
|
*/
|
||||||
|
|
||||||
// Math operators:
|
// Math operators:
|
||||||
var a: int, thisInt = 1234, thatInt = 5678;
|
var a: int, thisInt = 1234, thatInt = 5678;
|
||||||
@ -146,7 +170,7 @@ a <<= 3; // Left-bit-shift-equals (a = a << 10;)
|
|||||||
// Unlike other C family languages, there are no
|
// Unlike other C family languages, there are no
|
||||||
// pre/post-increment/decrement operators, such as:
|
// pre/post-increment/decrement operators, such as:
|
||||||
//
|
//
|
||||||
// ++j, --j, j++, j--
|
// ``++j``, ``--j``, ``j++``, ``j--``
|
||||||
|
|
||||||
// Swap operator:
|
// Swap operator:
|
||||||
var old_this = thisInt;
|
var old_this = thisInt;
|
||||||
@ -156,7 +180,9 @@ writeln((old_this == thatInt) && (old_that == thisInt));
|
|||||||
|
|
||||||
// Operator overloads can also be defined, as we'll see with procedures.
|
// Operator overloads can also be defined, as we'll see with procedures.
|
||||||
|
|
||||||
// Tuples
|
/*
|
||||||
|
Tuples
|
||||||
|
*/
|
||||||
|
|
||||||
// Tuples can be of the same type or different types.
|
// Tuples can be of the same type or different types.
|
||||||
var sameTup: 2*int = (10, -1);
|
var sameTup: 2*int = (10, -1);
|
||||||
@ -179,16 +205,18 @@ writeln(diffTup == (tupInt, tupReal, tupCplx));
|
|||||||
// They are also useful for writing a list of variables, as is common in debugging.
|
// They are also useful for writing a list of variables, as is common in debugging.
|
||||||
writeln((a,b,thisInt,thatInt,thisBool,thatBool));
|
writeln((a,b,thisInt,thatInt,thisBool,thatBool));
|
||||||
|
|
||||||
// Control Flow
|
/*
|
||||||
|
Control Flow
|
||||||
|
*/
|
||||||
|
|
||||||
// if - then - else works just like any other C-family language.
|
// ``if`` - ``then`` - ``else`` works just like any other C-family language.
|
||||||
if 10 < 100 then
|
if 10 < 100 then
|
||||||
writeln("All is well");
|
writeln("All is well");
|
||||||
|
|
||||||
if -1 < 1 then
|
if -1 < 1 then
|
||||||
writeln("Continuing to believe reality");
|
writeln("Continuing to believe reality");
|
||||||
else
|
else
|
||||||
writeln("Send mathematician, something is wrong");
|
writeln("Send mathematician, something's wrong");
|
||||||
|
|
||||||
// You can use parentheses if you prefer.
|
// You can use parentheses if you prefer.
|
||||||
if (10 > 100) {
|
if (10 > 100) {
|
||||||
@ -209,11 +237,11 @@ if a % 3 == 0 {
|
|||||||
writeln(b, " is divided by 3 with a remainder of 2.");
|
writeln(b, " is divided by 3 with a remainder of 2.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ternary: if - then - else in a statement.
|
// Ternary: ``if`` - ``then`` - ``else`` in a statement.
|
||||||
var maximum = if thisInt < thatInt then thatInt else thisInt;
|
var maximum = if thisInt < thatInt then thatInt else thisInt;
|
||||||
|
|
||||||
// select statements are much like switch statements in other languages.
|
// ``select`` statements are much like switch statements in other languages.
|
||||||
// However, select statements do not cascade like in C or Java.
|
// However, ``select`` statements don't cascade like in C or Java.
|
||||||
var inputOption = "anOption";
|
var inputOption = "anOption";
|
||||||
select inputOption {
|
select inputOption {
|
||||||
when "anOption" do writeln("Chose 'anOption'");
|
when "anOption" do writeln("Chose 'anOption'");
|
||||||
@ -223,11 +251,11 @@ select inputOption {
|
|||||||
}
|
}
|
||||||
otherwise {
|
otherwise {
|
||||||
writeln("Any other Input");
|
writeln("Any other Input");
|
||||||
writeln("the otherwise case does not need a do if the body is one line");
|
writeln("the otherwise case doesn't need a do if the body is one line");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// while and do-while loops also behave like their C counterparts.
|
// ``while`` and ``do``-``while`` loops also behave like their C counterparts.
|
||||||
var j: int = 1;
|
var j: int = 1;
|
||||||
var jSum: int = 0;
|
var jSum: int = 0;
|
||||||
while (j <= 1000) {
|
while (j <= 1000) {
|
||||||
@ -242,8 +270,8 @@ do {
|
|||||||
} while (j <= 10000);
|
} while (j <= 10000);
|
||||||
writeln(jSum);
|
writeln(jSum);
|
||||||
|
|
||||||
// for loops are much like those in Python in that they iterate over a
|
// ``for`` loops are much like those in python in that they iterate over a
|
||||||
// range. Ranges (like the 1..10 expression below) are a first-class object
|
// range. Ranges (like the ``1..10`` expression below) are a first-class object
|
||||||
// in Chapel, and as such can be stored in variables.
|
// in Chapel, and as such can be stored in variables.
|
||||||
for i in 1..10 do write(i, ", ");
|
for i in 1..10 do write(i, ", ");
|
||||||
writeln();
|
writeln();
|
||||||
@ -261,7 +289,9 @@ for x in 1..10 {
|
|||||||
writeln();
|
writeln();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ranges and Domains
|
/*
|
||||||
|
Ranges and Domains
|
||||||
|
*/
|
||||||
|
|
||||||
// For-loops and arrays both use ranges and domains to define an index set that
|
// For-loops and arrays both use ranges and domains to define an index set that
|
||||||
// can be iterated over. Ranges are single dimensional integer indices, while
|
// can be iterated over. Ranges are single dimensional integer indices, while
|
||||||
@ -277,17 +307,18 @@ var rangeEmpty: range = 100..-100; // this is valid but contains no indices
|
|||||||
var range1toInf: range(boundedType=BoundedRangeType.boundedLow) = 1.. ; // 1, 2, 3, 4, 5, ...
|
var range1toInf: range(boundedType=BoundedRangeType.boundedLow) = 1.. ; // 1, 2, 3, 4, 5, ...
|
||||||
var rangeNegInfTo1 = ..1; // ..., -4, -3, -2, -1, 0, 1
|
var rangeNegInfTo1 = ..1; // ..., -4, -3, -2, -1, 0, 1
|
||||||
|
|
||||||
// Ranges can be strided (and reversed) using the by operator.
|
// Ranges can be strided (and reversed) using the ``by`` operator.
|
||||||
var range2to10by2: range(stridable=true) = 2..10 by 2; // 2, 4, 6, 8, 10
|
var range2to10by2: range(stridable=true) = 2..10 by 2; // 2, 4, 6, 8, 10
|
||||||
var reverse2to10by2 = 2..10 by -2; // 10, 8, 6, 4, 2
|
var reverse2to10by2 = 2..10 by -2; // 10, 8, 6, 4, 2
|
||||||
|
|
||||||
var trapRange = 10..1 by -1; // Do not be fooled, this is still an empty range
|
var trapRange = 10..1 by -1; // Do not be fooled, this is still an empty range
|
||||||
writeln("Size of range ", trapRange, " = ", trapRange.length);
|
writeln("Size of range '", trapRange, "' = ", trapRange.size);
|
||||||
|
|
||||||
// Note: range(boundedType= ...) and range(stridable= ...) are only
|
// Note: ``range(boundedType= ...)`` and ``range(stridable= ...)`` are only
|
||||||
// necessary if we explicitly type the variable.
|
// necessary if we explicitly type the variable.
|
||||||
|
|
||||||
// The end point of a range can be determined using the count (#) operator.
|
// The end point of a range can be computed by specifying the total size
|
||||||
|
// of the range using the count (``#``) operator.
|
||||||
var rangeCount: range = -5..#12; // range from -5 to 6
|
var rangeCount: range = -5..#12; // range from -5 to 6
|
||||||
|
|
||||||
// Operators can be mixed.
|
// Operators can be mixed.
|
||||||
@ -297,8 +328,8 @@ writeln(rangeCountBy);
|
|||||||
// Properties of the range can be queried.
|
// Properties of the range can be queried.
|
||||||
// In this example, printing the first index, last index, number of indices,
|
// In this example, printing the first index, last index, number of indices,
|
||||||
// stride, and if 2 is include in the range.
|
// stride, and if 2 is include in the range.
|
||||||
writeln((rangeCountBy.first, rangeCountBy.last, rangeCountBy.length,
|
writeln((rangeCountBy.first, rangeCountBy.last, rangeCountBy.size,
|
||||||
rangeCountBy.stride, rangeCountBy.member(2)));
|
rangeCountBy.stride, rangeCountBy.contains(2)));
|
||||||
|
|
||||||
for i in rangeCountBy {
|
for i in rangeCountBy {
|
||||||
write(i, if i == rangeCountBy.last then "\n" else ", ");
|
write(i, if i == rangeCountBy.last then "\n" else ", ");
|
||||||
@ -322,7 +353,7 @@ for idx in twoDimensions do
|
|||||||
write(idx, ", ");
|
write(idx, ", ");
|
||||||
writeln();
|
writeln();
|
||||||
|
|
||||||
// These tuples can also be deconstructed.
|
// These tuples can also be destructured.
|
||||||
for (x,y) in twoDimensions {
|
for (x,y) in twoDimensions {
|
||||||
write("(", x, ", ", y, ")", ", ");
|
write("(", x, ", ", y, ")", ", ");
|
||||||
}
|
}
|
||||||
@ -352,7 +383,9 @@ var domainB = {-5..5, 1..10};
|
|||||||
var domainC = domainA[domainB];
|
var domainC = domainA[domainB];
|
||||||
writeln((domainA, domainB, domainC));
|
writeln((domainA, domainB, domainC));
|
||||||
|
|
||||||
// Arrays
|
/*
|
||||||
|
Arrays
|
||||||
|
*/
|
||||||
|
|
||||||
// Arrays are similar to those of other languages.
|
// Arrays are similar to those of other languages.
|
||||||
// Their sizes are defined using domains that represent their indices.
|
// Their sizes are defined using domains that represent their indices.
|
||||||
@ -364,9 +397,9 @@ for i in 1..10 do
|
|||||||
intArray[i] = -i;
|
intArray[i] = -i;
|
||||||
writeln(intArray);
|
writeln(intArray);
|
||||||
|
|
||||||
// We cannot access intArray[0] because it exists outside
|
// We cannot access ``intArray[0]`` because it exists outside
|
||||||
// of the index set, {1..10}, we defined it to have.
|
// of the index set, ``{1..10}``, we defined it to have.
|
||||||
// intArray[11] is illegal for the same reason.
|
// ``intArray[11]`` is illegal for the same reason.
|
||||||
var realDomain: domain(2) = {1..5,1..7};
|
var realDomain: domain(2) = {1..5,1..7};
|
||||||
var realArray: [realDomain] real;
|
var realArray: [realDomain] real;
|
||||||
var realArray2: [1..5,1..7] real; // equivalent
|
var realArray2: [1..5,1..7] real; // equivalent
|
||||||
@ -396,9 +429,9 @@ for value in realArray {
|
|||||||
writeln(rSum, "\n", realArray);
|
writeln(rSum, "\n", realArray);
|
||||||
|
|
||||||
// Associative arrays (dictionaries) can be created using associative domains.
|
// Associative arrays (dictionaries) can be created using associative domains.
|
||||||
var dictDomain: domain(string) = { "one", "two" };
|
var dictDomain: domain(string) = { "one", "two", "three"};
|
||||||
var dict: [dictDomain] int = ["one" => 1, "two" => 2];
|
var dict: [dictDomain] int = ["one" => 1, "two" => 2, "three" => 3];
|
||||||
dict["three"] = 3; // Adds 'three' to 'dictDomain' implicitly
|
|
||||||
for key in dictDomain.sorted() do
|
for key in dictDomain.sorted() do
|
||||||
writeln(dict[key]);
|
writeln(dict[key]);
|
||||||
|
|
||||||
@ -407,9 +440,9 @@ for key in dictDomain.sorted() do
|
|||||||
var thisArray : [0..5] int = [0,1,2,3,4,5];
|
var thisArray : [0..5] int = [0,1,2,3,4,5];
|
||||||
var thatArray : [0..5] int;
|
var thatArray : [0..5] int;
|
||||||
|
|
||||||
// First, simply assign one to the other. This copies thisArray into
|
// First, simply assign one to the other. This copies ``thisArray`` into
|
||||||
// thatArray, instead of just creating a reference. Therefore, modifying
|
// ``thatArray``, instead of just creating a reference. Therefore, modifying
|
||||||
// thisArray does not also modify thatArray.
|
// ``thisArray`` does not also modify ``thatArray``.
|
||||||
|
|
||||||
thatArray = thisArray;
|
thatArray = thisArray;
|
||||||
thatArray[1] = -1;
|
thatArray[1] = -1;
|
||||||
@ -425,7 +458,7 @@ var thisPlusThat = thisArray + thatArray;
|
|||||||
writeln(thisPlusThat);
|
writeln(thisPlusThat);
|
||||||
|
|
||||||
// Moving on, arrays and loops can also be expressions, where the loop
|
// Moving on, arrays and loops can also be expressions, where the loop
|
||||||
// body expression is the result of each iteration.
|
// body's expression is the result of each iteration.
|
||||||
var arrayFromLoop = for i in 1..10 do i;
|
var arrayFromLoop = for i in 1..10 do i;
|
||||||
writeln(arrayFromLoop);
|
writeln(arrayFromLoop);
|
||||||
|
|
||||||
@ -435,14 +468,16 @@ var evensOrFives = for i in 1..10 do if (i % 2 == 0 || i % 5 == 0) then i;
|
|||||||
writeln(arrayFromLoop);
|
writeln(arrayFromLoop);
|
||||||
|
|
||||||
// Array expressions can also be written with a bracket notation.
|
// Array expressions can also be written with a bracket notation.
|
||||||
// Note: this syntax uses the forall parallel concept discussed later.
|
// Note: this syntax uses the ``forall`` parallel concept discussed later.
|
||||||
var evensOrFivesAgain = [i in 1..10] if (i % 2 == 0 || i % 5 == 0) then i;
|
var evensOrFivesAgain = [i in 1..10] if (i % 2 == 0 || i % 5 == 0) then i;
|
||||||
|
|
||||||
// They can also be written over the values of the array.
|
// They can also be written over the values of the array.
|
||||||
arrayFromLoop = [value in arrayFromLoop] value + 1;
|
arrayFromLoop = [value in arrayFromLoop] value + 1;
|
||||||
|
|
||||||
|
|
||||||
// Procedures
|
/*
|
||||||
|
Procedures
|
||||||
|
*/
|
||||||
|
|
||||||
// Chapel procedures have similar syntax functions in other languages.
|
// Chapel procedures have similar syntax functions in other languages.
|
||||||
proc fibonacci(n : int) : int {
|
proc fibonacci(n : int) : int {
|
||||||
@ -482,10 +517,10 @@ writeln(defaultsProc(x=11));
|
|||||||
writeln(defaultsProc(x=12, y=5.432));
|
writeln(defaultsProc(x=12, y=5.432));
|
||||||
writeln(defaultsProc(y=9.876, x=13));
|
writeln(defaultsProc(y=9.876, x=13));
|
||||||
|
|
||||||
// The ? operator is called the query operator, and is used to take
|
// The ``?`` operator is called the query operator, and is used to take
|
||||||
// undetermined values like tuple or array sizes and generic types.
|
// undetermined values like tuple or array sizes and generic types.
|
||||||
// For example, taking arrays as parameters. The query operator is used to
|
// For example, taking arrays as parameters. The query operator is used to
|
||||||
// determine the domain of A. This is uesful for defining the return type,
|
// determine the domain of ``A``. This is useful for defining the return type,
|
||||||
// though it's not required.
|
// though it's not required.
|
||||||
proc invertArray(A: [?D] int): [D] int{
|
proc invertArray(A: [?D] int): [D] int{
|
||||||
for a in A do a = -a;
|
for a in A do a = -a;
|
||||||
@ -509,7 +544,7 @@ genericProc(1, 2);
|
|||||||
genericProc(1.2, 2.3);
|
genericProc(1.2, 2.3);
|
||||||
genericProc(1.0+2.0i, 3.0+4.0i);
|
genericProc(1.0+2.0i, 3.0+4.0i);
|
||||||
|
|
||||||
// We can also enforce a form of polymorphism with the where clause
|
// We can also enforce a form of polymorphism with the ``where`` clause
|
||||||
// This allows the compiler to decide which function to use.
|
// This allows the compiler to decide which function to use.
|
||||||
// Note: That means that all information needs to be known at compile-time.
|
// Note: That means that all information needs to be known at compile-time.
|
||||||
// The param modifier on the arg is used to enforce this constraint.
|
// The param modifier on the arg is used to enforce this constraint.
|
||||||
@ -526,13 +561,13 @@ proc whereProc(param N : int): void
|
|||||||
whereProc(10);
|
whereProc(10);
|
||||||
whereProc(-1);
|
whereProc(-1);
|
||||||
|
|
||||||
// whereProc(0) would result in a compiler error because there
|
// ``whereProc(0)`` would result in a compiler error because there
|
||||||
// are no functions that satisfy the where clause's condition.
|
// are no functions that satisfy the ``where`` clause's condition.
|
||||||
// We could have defined a whereProc without a where clause
|
// We could have defined a ``whereProc`` without a ``where`` clause
|
||||||
// that would then have served as a catch all for all the other cases
|
// that would then have served as a catch all for all the other cases
|
||||||
// (of which there is only one).
|
// (of which there is only one).
|
||||||
|
|
||||||
// where clauses can also be used to constrain based on argument type.
|
// ``where`` clauses can also be used to constrain based on argument type.
|
||||||
proc whereType(x: ?t) where t == int {
|
proc whereType(x: ?t) where t == int {
|
||||||
writeln("Inside 'int' version of 'whereType': ", x);
|
writeln("Inside 'int' version of 'whereType': ", x);
|
||||||
}
|
}
|
||||||
@ -544,7 +579,9 @@ proc whereType(x: ?t) {
|
|||||||
whereType(42);
|
whereType(42);
|
||||||
whereType("hello");
|
whereType("hello");
|
||||||
|
|
||||||
// Intents
|
/*
|
||||||
|
Intents
|
||||||
|
*/
|
||||||
|
|
||||||
/* Intent modifiers on the arguments convey how those arguments are passed to the procedure.
|
/* Intent modifiers on the arguments convey how those arguments are passed to the procedure.
|
||||||
|
|
||||||
@ -571,7 +608,7 @@ intentsProc(inVar, outVar, inoutVar, refVar);
|
|||||||
writeln("Outside After: ", (inVar, outVar, inoutVar, refVar));
|
writeln("Outside After: ", (inVar, outVar, inoutVar, refVar));
|
||||||
|
|
||||||
// Similarly, we can define intents on the return type.
|
// Similarly, we can define intents on the return type.
|
||||||
// refElement returns a reference to an element of array.
|
// ``refElement`` returns a reference to an element of array.
|
||||||
// This makes more practical sense for class methods where references to
|
// This makes more practical sense for class methods where references to
|
||||||
// elements in a data-structure are returned via a method or iterator.
|
// elements in a data-structure are returned via a method or iterator.
|
||||||
proc refElement(array : [?D] ?T, idx) ref : T {
|
proc refElement(array : [?D] ?T, idx) ref : T {
|
||||||
@ -586,14 +623,16 @@ refToElem = -2; // modify reference which modifies actual value in array
|
|||||||
writeln(refToElem);
|
writeln(refToElem);
|
||||||
writeln(myChangingArray);
|
writeln(myChangingArray);
|
||||||
|
|
||||||
// Operator Definitions
|
/*
|
||||||
|
Operator Definitions
|
||||||
|
*/
|
||||||
|
|
||||||
// Chapel allows for operators to be overloaded.
|
// Chapel allows for operators to be overloaded.
|
||||||
// We can define the unary operators:
|
// We can define the unary operators:
|
||||||
// + - ! ~
|
// ``+ - ! ~``
|
||||||
// and the binary operators:
|
// and the binary operators:
|
||||||
// + - * / % ** == <= >= < > << >> & | ˆ by
|
// ``+ - * / % ** == <= >= < > << >> & | ˆ by``
|
||||||
// += -= *= /= %= **= &= |= ˆ= <<= >>= <=>
|
// ``+= -= *= /= %= **= &= |= ˆ= <<= >>= <=>``
|
||||||
|
|
||||||
// Boolean exclusive or operator.
|
// Boolean exclusive or operator.
|
||||||
proc ^(left : bool, right : bool): bool {
|
proc ^(left : bool, right : bool): bool {
|
||||||
@ -605,25 +644,28 @@ writeln(false ^ true);
|
|||||||
writeln(true ^ false);
|
writeln(true ^ false);
|
||||||
writeln(false ^ false);
|
writeln(false ^ false);
|
||||||
|
|
||||||
// Define a * operator on any two types that returns a tuple of those types.
|
// Define a ``*`` operator on any two types that returns a tuple of those types.
|
||||||
proc *(left : ?ltype, right : ?rtype): (ltype, rtype) {
|
proc *(left : ?ltype, right : ?rtype): (ltype, rtype) {
|
||||||
writeln("\tIn our '*' overload!");
|
writeln("\tIn our '*' overload!");
|
||||||
return (left, right);
|
return (left, right);
|
||||||
}
|
}
|
||||||
|
|
||||||
writeln(1 * "a"); // Uses our * operator.
|
writeln(1 * "a"); // Uses our ``*`` operator.
|
||||||
writeln(1 * 2); // Uses the default * operator.
|
writeln(1 * 2); // Uses the default ``*`` operator.
|
||||||
|
|
||||||
// Note: You could break everything if you get careless with your overloads.
|
// Note: You could break everything if you get careless with your overloads.
|
||||||
// This here will break everything. Don't do it.
|
// This here will break everything. Don't do it.
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
||||||
proc +(left: int, right: int): int {
|
proc +(left: int, right: int): int {
|
||||||
return left - right;
|
return left - right;
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Iterators
|
/*
|
||||||
|
Iterators
|
||||||
|
*/
|
||||||
|
|
||||||
// Iterators are sisters to the procedure, and almost everything about
|
// Iterators are sisters to the procedure, and almost everything about
|
||||||
// procedures also applies to iterators. However, instead of returning a single
|
// procedures also applies to iterators. However, instead of returning a single
|
||||||
@ -656,7 +698,7 @@ for i in absolutelyNothing(10) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// We can zipper together two or more iterators (who have the same number
|
// We can zipper together two or more iterators (who have the same number
|
||||||
// of iterations) using zip() to create a single zipped iterator, where each
|
// of iterations) using ``zip()`` to create a single zipped iterator, where each
|
||||||
// iteration of the zipped iterator yields a tuple of one value yielded
|
// iteration of the zipped iterator yields a tuple of one value yielded
|
||||||
// from each iterator.
|
// from each iterator.
|
||||||
for (positive, negative) in zip(1..5, -5..-1) do
|
for (positive, negative) in zip(1..5, -5..-1) do
|
||||||
@ -683,8 +725,7 @@ for (i, j) in zip(toThisArray.domain, -100..#5) {
|
|||||||
}
|
}
|
||||||
writeln(toThisArray);
|
writeln(toThisArray);
|
||||||
|
|
||||||
// This is very important in understanding why this statement exhibits a
|
// This is very important in understanding why this statement exhibits a runtime error.
|
||||||
// runtime error.
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
var iterArray : [1..10] int = [i in 1..10] if (i % 2 == 1) then i;
|
var iterArray : [1..10] int = [i in 1..10] if (i % 2 == 1) then i;
|
||||||
@ -695,8 +736,9 @@ writeln(toThisArray);
|
|||||||
// Because iterators can yield nothing, that iterator yields a different number
|
// Because iterators can yield nothing, that iterator yields a different number
|
||||||
// of things than the domain of the array or loop, which is not allowed.
|
// of things than the domain of the array or loop, which is not allowed.
|
||||||
|
|
||||||
// Classes
|
/*
|
||||||
|
Classes
|
||||||
|
*/
|
||||||
// Classes are similar to those in C++ and Java, allocated on the heap.
|
// Classes are similar to those in C++ and Java, allocated on the heap.
|
||||||
class MyClass {
|
class MyClass {
|
||||||
|
|
||||||
@ -704,13 +746,16 @@ class MyClass {
|
|||||||
var memberInt : int;
|
var memberInt : int;
|
||||||
var memberBool : bool = true;
|
var memberBool : bool = true;
|
||||||
|
|
||||||
// Explicitly defined initializer.
|
// By default, any class that doesn't define an initializer gets a
|
||||||
// We also get the compiler-generated initializer, with one argument per field.
|
// compiler-generated initializer, with one argument per field and
|
||||||
// Note that soon there will be no compiler-generated initializer when we
|
// the field's initial value as the argument's default value.
|
||||||
// define any initializer(s) explicitly.
|
// Alternatively, the user can define initializers manually as shown
|
||||||
proc init(val : real) {
|
// in the following commented-out routine:
|
||||||
this.memberInt = ceil(val): int;
|
//
|
||||||
}
|
/* // proc init(val : real) {
|
||||||
|
// this.memberInt = ceil(val): int;
|
||||||
|
// }
|
||||||
|
*/
|
||||||
|
|
||||||
// Explicitly defined deinitializer.
|
// Explicitly defined deinitializer.
|
||||||
// If we did not write one, we would get the compiler-generated deinitializer,
|
// If we did not write one, we would get the compiler-generated deinitializer,
|
||||||
@ -738,37 +783,45 @@ class MyClass {
|
|||||||
} // end MyClass
|
} // end MyClass
|
||||||
|
|
||||||
// Call compiler-generated initializer, using default value for memberBool.
|
// Call compiler-generated initializer, using default value for memberBool.
|
||||||
var myObject = new MyClass(10);
|
{
|
||||||
myObject = new MyClass(memberInt = 10); // Equivalent
|
var myObject = new owned MyClass(10);
|
||||||
writeln(myObject.getMemberInt());
|
myObject = new owned MyClass(memberInt = 10); // Equivalent
|
||||||
|
writeln(myObject.getMemberInt());
|
||||||
|
|
||||||
// Same, but provide a memberBool value explicitly.
|
// Same, but provide a memberBool value explicitly.
|
||||||
var myDiffObject = new MyClass(-1, true);
|
var myDiffObject = new owned MyClass(-1, true);
|
||||||
myDiffObject = new MyClass(memberInt = -1,
|
myDiffObject = new owned MyClass(memberInt = -1,
|
||||||
memberBool = true); // Equivalent
|
memberBool = true); // Equivalent
|
||||||
writeln(myDiffObject);
|
writeln(myDiffObject);
|
||||||
|
|
||||||
// Call the initializer we wrote.
|
// Similar, but rely on the default value of memberInt, passing in memberBool.
|
||||||
var myOtherObject = new MyClass(1.95);
|
var myThirdObject = new owned MyClass(memberBool = true);
|
||||||
myOtherObject = new MyClass(val = 1.95); // Equivalent
|
writeln(myThirdObject);
|
||||||
writeln(myOtherObject.getMemberInt());
|
|
||||||
|
|
||||||
// We can define an operator on our class as well, but
|
// If the user-defined initializer above had been uncommented, we could
|
||||||
// the definition has to be outside the class definition.
|
// make the following calls:
|
||||||
proc +(A : MyClass, B : MyClass) : MyClass {
|
//
|
||||||
return new MyClass(memberInt = A.getMemberInt() + B.getMemberInt(),
|
/* // var myOtherObject = new MyClass(1.95);
|
||||||
|
// myOtherObject = new MyClass(val = 1.95);
|
||||||
|
// writeln(myOtherObject.getMemberInt());
|
||||||
|
*/
|
||||||
|
|
||||||
|
// We can define an operator on our class as well, but
|
||||||
|
// the definition has to be outside the class definition.
|
||||||
|
proc +(A : MyClass, B : MyClass) : owned MyClass {
|
||||||
|
return
|
||||||
|
new owned MyClass(memberInt = A.getMemberInt() + B.getMemberInt(),
|
||||||
memberBool = A.getMemberBool() || B.getMemberBool());
|
memberBool = A.getMemberBool() || B.getMemberBool());
|
||||||
|
}
|
||||||
|
|
||||||
|
var plusObject = myObject + myDiffObject;
|
||||||
|
writeln(plusObject);
|
||||||
|
|
||||||
|
// Destruction of an object: calls the deinit() routine and frees its memory.
|
||||||
|
// ``unmanaged`` variables should have ``delete`` called on them.
|
||||||
|
// ``owned`` variables are destroyed when they go out of scope.
|
||||||
}
|
}
|
||||||
|
|
||||||
var plusObject = myObject + myDiffObject;
|
|
||||||
writeln(plusObject);
|
|
||||||
|
|
||||||
// Destruction.
|
|
||||||
delete myObject;
|
|
||||||
delete myDiffObject;
|
|
||||||
delete myOtherObject;
|
|
||||||
delete plusObject;
|
|
||||||
|
|
||||||
// Classes can inherit from one or more parent classes
|
// Classes can inherit from one or more parent classes
|
||||||
class MyChildClass : MyClass {
|
class MyChildClass : MyClass {
|
||||||
var memberComplex: complex;
|
var memberComplex: complex;
|
||||||
@ -780,42 +833,46 @@ class GenericClass {
|
|||||||
var classDomain: domain(1);
|
var classDomain: domain(1);
|
||||||
var classArray: [classDomain] classType;
|
var classArray: [classDomain] classType;
|
||||||
|
|
||||||
// Explicit constructor.
|
// Explicit initializer.
|
||||||
proc GenericClass(type classType, elements : int) {
|
proc init(type classType, elements : int) {
|
||||||
this.classDomain = {1..#elements};
|
this.classType = classType;
|
||||||
|
this.classDomain = {1..elements};
|
||||||
|
// all generic and const fields must be initialized in "phase 1" prior
|
||||||
|
// to a call to the superclass initializer.
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy constructor.
|
// Copy-style initializer.
|
||||||
// Note: We still have to put the type as an argument, but we can
|
// Note: We include a type argument whose default is the type of the first
|
||||||
// default to the type of the other object using the query (?) operator.
|
// argument. This lets our initializer copy classes of different
|
||||||
// Further, we can take advantage of this to allow our copy constructor
|
// types and cast on the fly.
|
||||||
// to copy classes of different types and cast on the fly.
|
proc init(other : GenericClass(?),
|
||||||
proc GenericClass(other : GenericClass(?otherType),
|
type classType = other.classType) {
|
||||||
type classType = otherType) {
|
this.classType = classType;
|
||||||
this.classDomain = other.classDomain;
|
this.classDomain = other.classDomain;
|
||||||
// Copy and cast
|
this.classArray = for o in other do o: classType; // copy and cast
|
||||||
for idx in this.classDomain do this[idx] = other[idx] : classType;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Define bracket notation on a GenericClass
|
// Define bracket notation on a GenericClass
|
||||||
// object so it can behave like a normal array
|
// object so it can behave like a normal array
|
||||||
// i.e. objVar[i] or objVar(i)
|
// i.e. ``objVar[i]`` or ``objVar(i)``
|
||||||
proc this(i : int) ref : classType {
|
proc this(i : int) ref : classType {
|
||||||
return this.classArray[i];
|
return this.classArray[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Define an implicit iterator for the class
|
// Define an implicit iterator for the class
|
||||||
// to yield values from the array to a loop
|
// to yield values from the array to a loop
|
||||||
// i.e. for i in objVar do ...
|
// i.e. ``for i in objVar do ...``
|
||||||
iter these() ref : classType {
|
iter these() ref : classType {
|
||||||
for i in this.classDomain do
|
for i in this.classDomain do
|
||||||
yield this[i];
|
yield this[i];
|
||||||
}
|
}
|
||||||
} // end GenericClass
|
} // end GenericClass
|
||||||
|
|
||||||
|
// Allocate an owned instance of our class
|
||||||
|
var realList = new owned GenericClass(real, 10);
|
||||||
|
|
||||||
// We can assign to the member array of the object using the bracket
|
// We can assign to the member array of the object using the bracket
|
||||||
// notation that we defined.
|
// notation that we defined.
|
||||||
var realList = new GenericClass(real, 10);
|
|
||||||
for i in realList.classDomain do realList[i] = i + 1.0;
|
for i in realList.classDomain do realList[i] = i + 1.0;
|
||||||
|
|
||||||
// We can iterate over the values in our list with the iterator
|
// We can iterate over the values in our list with the iterator
|
||||||
@ -823,23 +880,25 @@ for i in realList.classDomain do realList[i] = i + 1.0;
|
|||||||
for value in realList do write(value, ", ");
|
for value in realList do write(value, ", ");
|
||||||
writeln();
|
writeln();
|
||||||
|
|
||||||
// Make a copy of realList using the copy constructor.
|
// Make a copy of realList using the copy initializer.
|
||||||
var copyList = new GenericClass(realList);
|
var copyList = new owned GenericClass(realList);
|
||||||
for value in copyList do write(value, ", ");
|
for value in copyList do write(value, ", ");
|
||||||
writeln();
|
writeln();
|
||||||
|
|
||||||
// Make a copy of realList and change the type, also using the copy constructor.
|
// Make a copy of realList and change the type, also using the copy initializer.
|
||||||
var copyNewTypeList = new GenericClass(realList, int);
|
var copyNewTypeList = new owned GenericClass(realList, int);
|
||||||
for value in copyNewTypeList do write(value, ", ");
|
for value in copyNewTypeList do write(value, ", ");
|
||||||
writeln();
|
writeln();
|
||||||
|
|
||||||
|
|
||||||
// Modules
|
/*
|
||||||
|
Modules
|
||||||
|
*/
|
||||||
|
|
||||||
// Modules are Chapel's way of managing name spaces.
|
// Modules are Chapel's way of managing name spaces.
|
||||||
// The files containing these modules do not need to be named after the modules
|
// The files containing these modules do not need to be named after the modules
|
||||||
// (as in Java), but files implicitly name modules.
|
// (as in Java), but files implicitly name modules.
|
||||||
// For example, this file implicitly names the learnChapelInYMinutes module
|
// For example, this file implicitly names the ``learnChapelInYMinutes`` module
|
||||||
|
|
||||||
module OurModule {
|
module OurModule {
|
||||||
|
|
||||||
@ -870,21 +929,23 @@ module OurModule {
|
|||||||
}
|
}
|
||||||
} // end OurModule
|
} // end OurModule
|
||||||
|
|
||||||
// Using OurModule also uses all the modules it uses.
|
// Using ``OurModule`` also uses all the modules it uses.
|
||||||
// Since OurModule uses Time, we also use Time.
|
// Since ``OurModule`` uses ``Time``, we also use ``Time``.
|
||||||
use OurModule;
|
use OurModule;
|
||||||
|
|
||||||
// At this point we have not used ChildModule or SiblingModule so
|
// At this point we have not used ``ChildModule`` or ``SiblingModule`` so
|
||||||
// their symbols (i.e. foo) are not available to us. However, the module
|
// their symbols (i.e. ``foo``) are not available to us. However, the module
|
||||||
// names are available, and we can explicitly call foo() through them.
|
// names are available, and we can explicitly call ``foo()`` through them.
|
||||||
SiblingModule.foo();
|
SiblingModule.foo();
|
||||||
OurModule.ChildModule.foo();
|
OurModule.ChildModule.foo();
|
||||||
|
|
||||||
// Now we use ChildModule, enabling unqualified calls.
|
// Now we use ``ChildModule``, enabling unqualified calls.
|
||||||
use ChildModule;
|
use ChildModule;
|
||||||
foo();
|
foo();
|
||||||
|
|
||||||
// Parallelism
|
/*
|
||||||
|
Parallelism
|
||||||
|
*/
|
||||||
|
|
||||||
// In other languages, parallelism is typically done with
|
// In other languages, parallelism is typically done with
|
||||||
// complicated libraries and strange class structure hierarchies.
|
// complicated libraries and strange class structure hierarchies.
|
||||||
@ -894,9 +955,9 @@ foo();
|
|||||||
// executed.
|
// executed.
|
||||||
proc main() {
|
proc main() {
|
||||||
|
|
||||||
// A begin statement will spin the body of that statement off
|
// A ``begin`` statement will spin the body of that statement off
|
||||||
// into one new task.
|
// into one new task.
|
||||||
// A sync statement will ensure that the progress of the main
|
// A ``sync`` statement will ensure that the progress of the main
|
||||||
// task will not progress until the children have synced back up.
|
// task will not progress until the children have synced back up.
|
||||||
|
|
||||||
sync {
|
sync {
|
||||||
@ -913,7 +974,7 @@ proc main() {
|
|||||||
writeln("fibonacci(",n,") = ", fibonacci(n));
|
writeln("fibonacci(",n,") = ", fibonacci(n));
|
||||||
}
|
}
|
||||||
|
|
||||||
// A cobegin statement will spin each statement of the body into one new
|
// A ``cobegin`` statement will spin each statement of the body into one new
|
||||||
// task. Notice here that the prints from each statement may happen in any
|
// task. Notice here that the prints from each statement may happen in any
|
||||||
// order.
|
// order.
|
||||||
cobegin {
|
cobegin {
|
||||||
@ -929,17 +990,17 @@ proc main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// A coforall loop will create a new task for EACH iteration.
|
// A ``coforall`` loop will create a new task for EACH iteration.
|
||||||
// Again we see that prints happen in any order.
|
// Again we see that prints happen in any order.
|
||||||
// NOTE: coforall should be used only for creating tasks!
|
// NOTE: ``coforall`` should be used only for creating tasks!
|
||||||
// Using it to iterating over a structure is very a bad idea!
|
// Using it to iterating over a structure is very a bad idea!
|
||||||
var num_tasks = 10; // Number of tasks we want
|
var num_tasks = 10; // Number of tasks we want
|
||||||
coforall taskID in 1..#num_tasks {
|
coforall taskID in 1..num_tasks {
|
||||||
writeln("Hello from task# ", taskID);
|
writeln("Hello from task# ", taskID);
|
||||||
}
|
}
|
||||||
|
|
||||||
// forall loops are another parallel loop, but only create a smaller number
|
// ``forall`` loops are another parallel loop, but only create a smaller number
|
||||||
// of tasks, specifically --dataParTasksPerLocale= number of tasks.
|
// of tasks, specifically ``--dataParTasksPerLocale=`` number of tasks.
|
||||||
forall i in 1..100 {
|
forall i in 1..100 {
|
||||||
write(i, ", ");
|
write(i, ", ");
|
||||||
}
|
}
|
||||||
@ -951,10 +1012,10 @@ proc main() {
|
|||||||
// (1..3, 4..6, or 7..9) doing that chunk serially, but each task happens
|
// (1..3, 4..6, or 7..9) doing that chunk serially, but each task happens
|
||||||
// in parallel. Your results may depend on your machine and configuration
|
// in parallel. Your results may depend on your machine and configuration
|
||||||
|
|
||||||
// For both the forall and coforall loops, the execution of the
|
// For both the ``forall`` and ``coforall`` loops, the execution of the
|
||||||
// parent task will not continue until all the children sync up.
|
// parent task will not continue until all the children sync up.
|
||||||
|
|
||||||
// forall loops are particularly useful for parallel iteration over arrays.
|
// ``forall`` loops are particularly useful for parallel iteration over arrays.
|
||||||
// Lets run an experiment to see how much faster a parallel loop is
|
// Lets run an experiment to see how much faster a parallel loop is
|
||||||
use Time; // Import the Time module to use Timer objects
|
use Time; // Import the Time module to use Timer objects
|
||||||
var timer: Timer;
|
var timer: Timer;
|
||||||
@ -982,14 +1043,14 @@ proc main() {
|
|||||||
// the parallel loop went faster than the serial loop.
|
// the parallel loop went faster than the serial loop.
|
||||||
|
|
||||||
// The bracket style loop-expression described
|
// The bracket style loop-expression described
|
||||||
// much earlier implicitly uses a forall loop.
|
// much earlier implicitly uses a ``forall`` loop.
|
||||||
[val in myBigArray] val = 1 / val; // Parallel operation
|
[val in myBigArray] val = 1 / val; // Parallel operation
|
||||||
|
|
||||||
// Atomic variables, common to many languages, are ones whose operations
|
// Atomic variables, common to many languages, are ones whose operations
|
||||||
// occur uninterrupted. Multiple threads can therefore modify atomic
|
// occur uninterrupted. Multiple threads can therefore modify atomic
|
||||||
// variables and can know that their values are safe.
|
// variables and can know that their values are safe.
|
||||||
// Chapel atomic variables can be of type bool, int,
|
// Chapel atomic variables can be of type ``bool``, ``int``,
|
||||||
// uint, and real.
|
// ``uint``, and ``real``.
|
||||||
var uranium: atomic int;
|
var uranium: atomic int;
|
||||||
uranium.write(238); // atomically write a variable
|
uranium.write(238); // atomically write a variable
|
||||||
writeln(uranium.read()); // atomically read a variable
|
writeln(uranium.read()); // atomically read a variable
|
||||||
@ -1003,7 +1064,7 @@ proc main() {
|
|||||||
writeln("uranium was ", was, " but is now ", replaceWith);
|
writeln("uranium was ", was, " but is now ", replaceWith);
|
||||||
|
|
||||||
var isEqualTo = 235;
|
var isEqualTo = 235;
|
||||||
if uranium.compareExchange(isEqualTo, replaceWith) {
|
if uranium.compareAndSwap(isEqualTo, replaceWith) {
|
||||||
writeln("uranium was equal to ", isEqualTo,
|
writeln("uranium was equal to ", isEqualTo,
|
||||||
" so replaced value with ", replaceWith);
|
" so replaced value with ", replaceWith);
|
||||||
} else {
|
} else {
|
||||||
@ -1025,7 +1086,7 @@ proc main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// sync variables have two states: empty and full.
|
// ``sync`` variables have two states: empty and full.
|
||||||
// If you read an empty variable or write a full variable, you are waited
|
// If you read an empty variable or write a full variable, you are waited
|
||||||
// until the variable is full or empty again.
|
// until the variable is full or empty again.
|
||||||
var someSyncVar$: sync int; // varName$ is a convention not a law.
|
var someSyncVar$: sync int; // varName$ is a convention not a law.
|
||||||
@ -1043,9 +1104,8 @@ proc main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// single vars can only be written once. A read on an unwritten single
|
// ``single`` vars can only be written once. A read on an unwritten ``single``
|
||||||
// results in a wait, but when the variable has a value it can be read
|
// results in a wait, but when the variable has a value it can be read indefinitely.
|
||||||
// indefinitely.
|
|
||||||
var someSingleVar$: single int; // varName$ is a convention not a law.
|
var someSingleVar$: single int; // varName$ is a convention not a law.
|
||||||
sync {
|
sync {
|
||||||
begin { // Reader task
|
begin { // Reader task
|
||||||
@ -1063,7 +1123,7 @@ proc main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Here's an example using atomics and a sync variable to create a
|
// Here's an example using atomics and a ``sync`` variable to create a
|
||||||
// count-down mutex (also known as a multiplexer).
|
// count-down mutex (also known as a multiplexer).
|
||||||
var count: atomic int; // our counter
|
var count: atomic int; // our counter
|
||||||
var lock$: sync bool; // the mutex lock
|
var lock$: sync bool; // the mutex lock
|
||||||
@ -1074,7 +1134,7 @@ proc main() {
|
|||||||
// (full:unlocked / empty:locked)
|
// (full:unlocked / empty:locked)
|
||||||
// Also, writeXF() fills (F) the sync var regardless of its state (X)
|
// Also, writeXF() fills (F) the sync var regardless of its state (X)
|
||||||
|
|
||||||
coforall task in 1..#5 { // Generate tasks
|
coforall task in 1..5 { // Generate tasks
|
||||||
// Create a barrier
|
// Create a barrier
|
||||||
do {
|
do {
|
||||||
lock$; // Read lock$ (wait)
|
lock$; // Read lock$ (wait)
|
||||||
@ -1091,7 +1151,7 @@ proc main() {
|
|||||||
lock$.writeXF(true); // Set lock$ to full (signal)
|
lock$.writeXF(true); // Set lock$ to full (signal)
|
||||||
}
|
}
|
||||||
|
|
||||||
// We can define the operations + * & | ^ && || min max minloc maxloc
|
// We can define the operations ``+ * & | ^ && || min max minloc maxloc``
|
||||||
// over an entire array using scans and reductions.
|
// over an entire array using scans and reductions.
|
||||||
// Reductions apply the operation over the entire array and
|
// Reductions apply the operation over the entire array and
|
||||||
// result in a scalar value.
|
// result in a scalar value.
|
||||||
@ -1099,7 +1159,7 @@ proc main() {
|
|||||||
var sumOfValues = + reduce listOfValues;
|
var sumOfValues = + reduce listOfValues;
|
||||||
var maxValue = max reduce listOfValues; // 'max' give just max value
|
var maxValue = max reduce listOfValues; // 'max' give just max value
|
||||||
|
|
||||||
// maxloc gives max value and index of the max value.
|
// ``maxloc`` gives max value and index of the max value.
|
||||||
// Note: We have to zip the array and domain together with the zip iterator.
|
// Note: We have to zip the array and domain together with the zip iterator.
|
||||||
var (theMaxValue, idxOfMax) = maxloc reduce zip(listOfValues,
|
var (theMaxValue, idxOfMax) = maxloc reduce zip(listOfValues,
|
||||||
listOfValues.domain);
|
listOfValues.domain);
|
||||||
@ -1108,7 +1168,7 @@ proc main() {
|
|||||||
|
|
||||||
// Scans apply the operation incrementally and return an array with the
|
// Scans apply the operation incrementally and return an array with the
|
||||||
// values of the operation at that index as it progressed through the
|
// values of the operation at that index as it progressed through the
|
||||||
// array from array.domain.low to array.domain.high.
|
// array from ``array.domain.low`` to ``array.domain.high``.
|
||||||
var runningSumOfValues = + scan listOfValues;
|
var runningSumOfValues = + scan listOfValues;
|
||||||
var maxScan = max scan listOfValues;
|
var maxScan = max scan listOfValues;
|
||||||
writeln(runningSumOfValues);
|
writeln(runningSumOfValues);
|
||||||
|
Loading…
Reference in New Issue
Block a user