summaryrefslogtreecommitdiffhomepage
path: root/chapel.html.markdown
diff options
context:
space:
mode:
Diffstat (limited to 'chapel.html.markdown')
-rw-r--r--chapel.html.markdown1191
1 files changed, 1191 insertions, 0 deletions
diff --git a/chapel.html.markdown b/chapel.html.markdown
new file mode 100644
index 00000000..9190f462
--- /dev/null
+++ b/chapel.html.markdown
@@ -0,0 +1,1191 @@
+---
+language: chapel
+filename: learnchapel.chpl
+contributors:
+ - ["Ian J. Bertolacci", "https://www.cs.arizona.edu/~ianbertolacci/"]
+ - ["Ben Harshbarger", "https://github.com/benharsh/"]
+---
+
+You can read all about Chapel at [Cray's official Chapel website](https://chapel-lang.org).
+In short, Chapel is an open-source, high-productivity, parallel-programming
+language in development at Cray Inc., and is designed to run on multi-core PCs
+as well as multi-kilocore supercomputers.
+
+More information and support can be found at the bottom of this document.
+
+```chapel
+// Comments are C-family style
+
+// one line comment
+/*
+ multi-line comment
+*/
+
+// Basic printing
+
+write("Hello, ");
+writeln("World!");
+
+// write and writeln can take a list of things to print.
+// Each thing is printed right next to the others, so include your spacing!
+writeln("There are ", 3, " commas (\",\") in this line of code");
+
+// Different output channels:
+stdout.writeln("This goes to standard output, just like plain writeln() does");
+stderr.writeln("This goes to standard error");
+
+
+// Variables don't have to be explicitly typed as long as
+// the compiler can figure out the type that it will hold.
+// 10 is an int, so myVar is implicitly an int
+var myVar = 10;
+myVar = -10;
+var mySecondVar = myVar;
+// var anError; would be a compile-time error.
+
+// We can (and should) explicitly type things.
+var myThirdVar: real;
+var myFourthVar: real = -1.234;
+myThirdVar = myFourthVar;
+
+// Types
+
+// There are a number of basic types.
+var myInt: int = -1000; // Signed ints
+var myUint: uint = 1234; // Unsigned ints
+var myReal: real = 9.876; // Floating point numbers
+var myImag: imag = 5.0i; // Imaginary numbers
+var myCplx: complex = 10 + 9i; // Complex numbers
+myCplx = myInt + myImag; // Another way to form complex numbers
+var myBool: bool = false; // Booleans
+var myStr: string = "Some string..."; // Strings
+var singleQuoteStr = 'Another string...'; // String literal with single quotes
+
+// Some types can have sizes.
+var my8Int: int(8) = 10; // 8 bit (one byte) sized int;
+var my64Real: real(64) = 1.516; // 64 bit (8 bytes) sized real
+
+// Typecasting.
+var intFromReal = myReal : int;
+var intFromReal2: int = myReal : int;
+
+// Type aliasing.
+type chroma = int; // Type of a single hue
+type RGBColor = 3*chroma; // Type representing a full color
+var black: RGBColor = (0,0,0);
+var white: RGBColor = (255, 255, 255);
+
+// Constants and Parameters
+
+// A const is a constant, and cannot be changed after set in runtime.
+const almostPi: real = 22.0/7.0;
+
+// A param is a constant whose value must be known statically at
+// compile-time.
+param compileTimeConst: int = 16;
+
+// The config modifier allows values to be set at the command line.
+// Set with --varCmdLineArg=Value or --varCmdLineArg Value at runtime.
+config var varCmdLineArg: int = -123;
+config const constCmdLineArg: int = 777;
+
+// config param can be set at compile-time.
+// Set with --set paramCmdLineArg=value at compile-time.
+config param paramCmdLineArg: bool = false;
+writeln(varCmdLineArg, ", ", constCmdLineArg, ", ", paramCmdLineArg);
+
+// References
+
+// 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.
+// Here, refToActual refers to actual.
+var actual = 10;
+ref refToActual = actual;
+writeln(actual, " == ", refToActual); // prints the same value
+actual = -123; // modify actual (which refToActual refers to)
+writeln(actual, " == ", refToActual); // prints the same value
+refToActual = 99999999; // modify what refToActual refers to (which is actual)
+writeln(actual, " == ", refToActual); // prints the same value
+
+// Operators
+
+// Math operators:
+var a: int, thisInt = 1234, thatInt = 5678;
+a = thisInt + thatInt; // Addition
+a = thisInt * thatInt; // Multiplication
+a = thisInt - thatInt; // Subtraction
+a = thisInt / thatInt; // Division
+a = thisInt ** thatInt; // Exponentiation
+a = thisInt % thatInt; // Remainder (modulo)
+
+// Logical operators:
+var b: bool, thisBool = false, thatBool = true;
+b = thisBool && thatBool; // Logical and
+b = thisBool || thatBool; // Logical or
+b = !thisBool; // Logical negation
+
+// Relational operators:
+b = thisInt > thatInt; // Greater-than
+b = thisInt >= thatInt; // Greater-than-or-equal-to
+b = thisInt < a && a <= thatInt; // Less-than, and, less-than-or-equal-to
+b = thisInt != thatInt; // Not-equal-to
+b = thisInt == thatInt; // Equal-to
+
+// Bitwise operators:
+a = thisInt << 10; // Left-bit-shift by 10 bits;
+a = thatInt >> 5; // Right-bit-shift by 5 bits;
+a = ~thisInt; // Bitwise-negation
+a = thisInt ^ thatInt; // Bitwise exclusive-or
+
+// Compound assignment operators:
+a += thisInt; // Addition-equals (a = a + thisInt;)
+a *= thatInt; // Times-equals (a = a * thatInt;)
+b &&= thatBool; // Logical-and-equals (b = b && thatBool;)
+a <<= 3; // Left-bit-shift-equals (a = a << 10;)
+
+// Unlike other C family languages, there are no
+// pre/post-increment/decrement operators, such as:
+//
+// ++j, --j, j++, j--
+
+// Swap operator:
+var old_this = thisInt;
+var old_that = thatInt;
+thisInt <=> thatInt; // Swap the values of thisInt and thatInt
+writeln((old_this == thatInt) && (old_that == thisInt));
+
+// Operator overloads can also be defined, as we'll see with procedures.
+
+// Tuples
+
+// Tuples can be of the same type or different types.
+var sameTup: 2*int = (10, -1);
+var sameTup2 = (11, -6);
+var diffTup: (int,real,complex) = (5, 1.928, myCplx);
+var diffTupe2 = (7, 5.64, 6.0+1.5i);
+
+// Tuples can be accessed using square brackets or parentheses, and are
+// 1-indexed.
+writeln("(", sameTup[1], ",", sameTup(2), ")");
+writeln(diffTup);
+
+// Tuples can also be written into.
+diffTup(1) = -1;
+
+// Tuple values can be expanded into their own variables.
+var (tupInt, tupReal, tupCplx) = diffTup;
+writeln(diffTup == (tupInt, tupReal, tupCplx));
+
+// They are also useful for writing a list of variables, as is common in debugging.
+writeln((a,b,thisInt,thatInt,thisBool,thatBool));
+
+// Control Flow
+
+// if - then - else works just like any other C-family language.
+if 10 < 100 then
+ writeln("All is well");
+
+if -1 < 1 then
+ writeln("Continuing to believe reality");
+else
+ writeln("Send mathematician, something is wrong");
+
+// You can use parentheses if you prefer.
+if (10 > 100) {
+ writeln("Universe broken. Please reboot universe.");
+}
+
+if a % 2 == 0 {
+ writeln(a, " is even.");
+} else {
+ writeln(a, " is odd.");
+}
+
+if a % 3 == 0 {
+ writeln(a, " is even divisible by 3.");
+} else if a % 3 == 1 {
+ writeln(a, " is divided by 3 with a remainder of 1.");
+} else {
+ writeln(b, " is divided by 3 with a remainder of 2.");
+}
+
+// Ternary: if - then - else in a statement.
+var maximum = if thisInt < thatInt then thatInt else thisInt;
+
+// select statements are much like switch statements in other languages.
+// However, select statements do not cascade like in C or Java.
+var inputOption = "anOption";
+select inputOption {
+ when "anOption" do writeln("Chose 'anOption'");
+ when "otherOption" {
+ writeln("Chose 'otherOption'");
+ writeln("Which has a body");
+ }
+ otherwise {
+ writeln("Any other Input");
+ writeln("the otherwise case does not need a do if the body is one line");
+ }
+}
+
+// while and do-while loops also behave like their C counterparts.
+var j: int = 1;
+var jSum: int = 0;
+while (j <= 1000) {
+ jSum += j;
+ j += 1;
+}
+writeln(jSum);
+
+do {
+ jSum += j;
+ j += 1;
+} while (j <= 10000);
+writeln(jSum);
+
+// 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
+// in Chapel, and as such can be stored in variables.
+for i in 1..10 do write(i, ", ");
+writeln();
+
+var iSum: int = 0;
+for i in 1..1000 {
+ iSum += i;
+}
+writeln(iSum);
+
+for x in 1..10 {
+ for y in 1..10 {
+ write((x,y), "\t");
+ }
+ writeln();
+}
+
+// Ranges and Domains
+
+// 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
+// domains can be multi-dimensional and represent indices of different types.
+
+// They are first-class citizen types, and can be assigned into variables.
+var range1to10: range = 1..10; // 1, 2, 3, ..., 10
+var range2to11 = 2..11; // 2, 3, 4, ..., 11
+var rangeThisToThat: range = thisInt..thatInt; // using variables
+var rangeEmpty: range = 100..-100; // this is valid but contains no indices
+
+// Ranges can be unbounded.
+var range1toInf: range(boundedType=BoundedRangeType.boundedLow) = 1.. ; // 1, 2, 3, 4, 5, ...
+var rangeNegInfTo1 = ..1; // ..., -4, -3, -2, -1, 0, 1
+
+// 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 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
+writeln("Size of range ", trapRange, " = ", trapRange.length);
+
+// Note: range(boundedType= ...) and range(stridable= ...) are only
+// necessary if we explicitly type the variable.
+
+// The end point of a range can be determined using the count (#) operator.
+var rangeCount: range = -5..#12; // range from -5 to 6
+
+// Operators can be mixed.
+var rangeCountBy: range(stridable=true) = -5..#12 by 2; // -5, -3, -1, 1, 3, 5
+writeln(rangeCountBy);
+
+// Properties of the range can be queried.
+// In this example, printing the first index, last index, number of indices,
+// stride, and if 2 is include in the range.
+writeln((rangeCountBy.first, rangeCountBy.last, rangeCountBy.length,
+ rangeCountBy.stride, rangeCountBy.member(2)));
+
+for i in rangeCountBy {
+ write(i, if i == rangeCountBy.last then "\n" else ", ");
+}
+
+// Rectangular domains are defined using the same range syntax,
+// but they are required to be bounded (unlike ranges).
+var domain1to10: domain(1) = {1..10}; // 1D domain from 1..10;
+var twoDimensions: domain(2) = {-2..2,0..2}; // 2D domain over product of ranges
+var thirdDim: range = 1..16;
+var threeDims: domain(3) = {thirdDim, 1..10, 5..10}; // using a range variable
+
+// Domains can also be resized
+var resizedDom = {1..10};
+writeln("before, resizedDom = ", resizedDom);
+resizedDom = {-10..#10};
+writeln("after, resizedDom = ", resizedDom);
+
+// Indices can be iterated over as tuples.
+for idx in twoDimensions do
+ write(idx, ", ");
+writeln();
+
+// These tuples can also be deconstructed.
+for (x,y) in twoDimensions {
+ write("(", x, ", ", y, ")", ", ");
+}
+writeln();
+
+// Associative domains act like sets.
+var stringSet: domain(string); // empty set of strings
+stringSet += "a";
+stringSet += "b";
+stringSet += "c";
+stringSet += "a"; // Redundant add "a"
+stringSet -= "c"; // Remove "c"
+writeln(stringSet.sorted());
+
+// Associative domains can also have a literal syntax
+var intSet = {1, 2, 4, 5, 100};
+
+// Both ranges and domains can be sliced to produce a range or domain with the
+// intersection of indices.
+var rangeA = 1.. ; // range from 1 to infinity
+var rangeB = ..5; // range from negative infinity to 5
+var rangeC = rangeA[rangeB]; // resulting range is 1..5
+writeln((rangeA, rangeB, rangeC));
+
+var domainA = {1..10, 5..20};
+var domainB = {-5..5, 1..10};
+var domainC = domainA[domainB];
+writeln((domainA, domainB, domainC));
+
+// Arrays
+
+// Arrays are similar to those of other languages.
+// Their sizes are defined using domains that represent their indices.
+var intArray: [1..10] int;
+var intArray2: [{1..10}] int; // equivalent
+
+// They can be accessed using either brackets or parentheses
+for i in 1..10 do
+ intArray[i] = -i;
+writeln(intArray);
+
+// We cannot access intArray[0] because it exists outside
+// of the index set, {1..10}, we defined it to have.
+// intArray[11] is illegal for the same reason.
+var realDomain: domain(2) = {1..5,1..7};
+var realArray: [realDomain] real;
+var realArray2: [1..5,1..7] real; // equivalent
+var realArray3: [{1..5,1..7}] real; // equivalent
+
+for i in 1..5 {
+ for j in realDomain.dim(2) { // Only use the 2nd dimension of the domain
+ realArray[i,j] = -1.61803 * i + 0.5 * j; // Access using index list
+ var idx: 2*int = (i,j); // Note: 'index' is a keyword
+ realArray[idx] = - realArray[(i,j)]; // Index using tuples
+ }
+}
+
+// Arrays have domains as members, and can be iterated over as normal.
+for idx in realArray.domain { // Again, idx is a 2*int tuple
+ realArray[idx] = 1 / realArray[idx[1], idx[2]]; // Access by tuple and list
+}
+
+writeln(realArray);
+
+// The values of an array can also be iterated directly.
+var rSum: real = 0;
+for value in realArray {
+ rSum += value; // Read a value
+ value = rSum; // Write a value
+}
+writeln(rSum, "\n", realArray);
+
+// Associative arrays (dictionaries) can be created using associative domains.
+var dictDomain: domain(string) = { "one", "two" };
+var dict: [dictDomain] int = ["one" => 1, "two" => 2];
+dict["three"] = 3; // Adds 'three' to 'dictDomain' implicitly
+for key in dictDomain.sorted() do
+ writeln(dict[key]);
+
+// Arrays can be assigned to each other in a few different ways.
+// These arrays will be used in the example.
+var thisArray : [0..5] int = [0,1,2,3,4,5];
+var thatArray : [0..5] int;
+
+// First, simply assign one to the other. This copies thisArray into
+// thatArray, instead of just creating a reference. Therefore, modifying
+// thisArray does not also modify thatArray.
+
+thatArray = thisArray;
+thatArray[1] = -1;
+writeln((thisArray, thatArray));
+
+// Assign a slice from one array to a slice (of the same size) in the other.
+thatArray[4..5] = thisArray[1..2];
+writeln((thisArray, thatArray));
+
+// Operations can also be promoted to work on arrays. 'thisPlusThat' is also
+// an array.
+var thisPlusThat = thisArray + thatArray;
+writeln(thisPlusThat);
+
+// Moving on, arrays and loops can also be expressions, where the loop
+// body expression is the result of each iteration.
+var arrayFromLoop = for i in 1..10 do i;
+writeln(arrayFromLoop);
+
+// An expression can result in nothing, such as when filtering with an if-expression.
+var evensOrFives = for i in 1..10 do if (i % 2 == 0 || i % 5 == 0) then i;
+
+writeln(arrayFromLoop);
+
+// Array expressions can also be written with a bracket notation.
+// 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;
+
+// They can also be written over the values of the array.
+arrayFromLoop = [value in arrayFromLoop] value + 1;
+
+
+// Procedures
+
+// Chapel procedures have similar syntax functions in other languages.
+proc fibonacci(n : int) : int {
+ if n <= 1 then return n;
+ return fibonacci(n-1) + fibonacci(n-2);
+}
+
+// Input parameters can be untyped to create a generic procedure.
+proc doublePrint(thing): void {
+ write(thing, " ", thing, "\n");
+}
+
+// The return type can be inferred, as long as the compiler can figure it out.
+proc addThree(n) {
+ return n + 3;
+}
+
+doublePrint(addThree(fibonacci(20)));
+
+// It is also possible to take a variable number of parameters.
+proc maxOf(x ...?k) {
+ // x refers to a tuple of one type, with k elements
+ var maximum = x[1];
+ for i in 2..k do maximum = if maximum < x[i] then x[i] else maximum;
+ return maximum;
+}
+writeln(maxOf(1, -10, 189, -9071982, 5, 17, 20001, 42));
+
+// Procedures can have default parameter values, and
+// the parameters can be named in the call, even out of order.
+proc defaultsProc(x: int, y: real = 1.2634): (int,real) {
+ return (x,y);
+}
+
+writeln(defaultsProc(10));
+writeln(defaultsProc(x=11));
+writeln(defaultsProc(x=12, y=5.432));
+writeln(defaultsProc(y=9.876, x=13));
+
+// The ? operator is called the query operator, and is used to take
+// undetermined values like tuple or array sizes and generic types.
+// 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,
+// though it's not required.
+proc invertArray(A: [?D] int): [D] int{
+ for a in A do a = -a;
+ return A;
+}
+
+writeln(invertArray(intArray));
+
+// We can query the type of arguments to generic procedures.
+// Here we define a procedure that takes two arguments of
+// the same type, yet we don't define what that type is.
+proc genericProc(arg1 : ?valueType, arg2 : valueType): void {
+ select(valueType) {
+ when int do writeln(arg1, " and ", arg2, " are ints");
+ when real do writeln(arg1, " and ", arg2, " are reals");
+ otherwise writeln(arg1, " and ", arg2, " are somethings!");
+ }
+}
+
+genericProc(1, 2);
+genericProc(1.2, 2.3);
+genericProc(1.0+2.0i, 3.0+4.0i);
+
+// We can also enforce a form of polymorphism with the where clause
+// This allows the compiler to decide which function to use.
+// 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.
+proc whereProc(param N : int): void
+ where (N > 0) {
+ writeln("N is greater than 0");
+}
+
+proc whereProc(param N : int): void
+ where (N < 0) {
+ writeln("N is less than 0");
+}
+
+whereProc(10);
+whereProc(-1);
+
+// whereProc(0) would result in a compiler error because there
+// are no functions that satisfy the where clause's condition.
+// We could have defined a whereProc without a where clause
+// that would then have served as a catch all for all the other cases
+// (of which there is only one).
+
+// where clauses can also be used to constrain based on argument type.
+proc whereType(x: ?t) where t == int {
+ writeln("Inside 'int' version of 'whereType': ", x);
+}
+
+proc whereType(x: ?t) {
+ writeln("Inside general version of 'whereType': ", x);
+}
+
+whereType(42);
+whereType("hello");
+
+// Intents
+
+/* Intent modifiers on the arguments convey how those arguments are passed to the procedure.
+
+ * in: copy arg in, but not out
+ * out: copy arg out, but not in
+ * inout: copy arg in, copy arg out
+ * ref: pass arg by reference
+*/
+proc intentsProc(in inarg, out outarg, inout inoutarg, ref refarg) {
+ writeln("Inside Before: ", (inarg, outarg, inoutarg, refarg));
+ inarg = inarg + 100;
+ outarg = outarg + 100;
+ inoutarg = inoutarg + 100;
+ refarg = refarg + 100;
+ writeln("Inside After: ", (inarg, outarg, inoutarg, refarg));
+}
+
+var inVar: int = 1;
+var outVar: int = 2;
+var inoutVar: int = 3;
+var refVar: int = 4;
+writeln("Outside Before: ", (inVar, outVar, inoutVar, refVar));
+intentsProc(inVar, outVar, inoutVar, refVar);
+writeln("Outside After: ", (inVar, outVar, inoutVar, refVar));
+
+// Similarly, we can define intents on the return type.
+// refElement returns a reference to an element of array.
+// This makes more practical sense for class methods where references to
+// elements in a data-structure are returned via a method or iterator.
+proc refElement(array : [?D] ?T, idx) ref : T {
+ return array[idx];
+}
+
+var myChangingArray : [1..5] int = [1,2,3,4,5];
+writeln(myChangingArray);
+ref refToElem = refElement(myChangingArray, 5); // store reference to element in ref variable
+writeln(refToElem);
+refToElem = -2; // modify reference which modifies actual value in array
+writeln(refToElem);
+writeln(myChangingArray);
+
+// Operator Definitions
+
+// Chapel allows for operators to be overloaded.
+// We can define the unary operators:
+// + - ! ~
+// and the binary operators:
+// + - * / % ** == <= >= < > << >> & | ˆ by
+// += -= *= /= %= **= &= |= ˆ= <<= >>= <=>
+
+// Boolean exclusive or operator.
+proc ^(left : bool, right : bool): bool {
+ return (left || right) && !(left && right);
+}
+
+writeln(true ^ true);
+writeln(false ^ true);
+writeln(true ^ false);
+writeln(false ^ false);
+
+// Define a * operator on any two types that returns a tuple of those types.
+proc *(left : ?ltype, right : ?rtype): (ltype, rtype) {
+ writeln("\tIn our '*' overload!");
+ return (left, right);
+}
+
+writeln(1 * "a"); // Uses our * operator.
+writeln(1 * 2); // Uses the default * operator.
+
+// Note: You could break everything if you get careless with your overloads.
+// This here will break everything. Don't do it.
+
+/*
+ proc +(left: int, right: int): int {
+ return left - right;
+ }
+*/
+
+// Iterators
+
+// Iterators are sisters to the procedure, and almost everything about
+// procedures also applies to iterators. However, instead of returning a single
+// value, iterators may yield multiple values to a loop.
+//
+// This is useful when a complicated set or order of iterations is needed, as
+// it allows the code defining the iterations to be separate from the loop
+// body.
+iter oddsThenEvens(N: int): int {
+ for i in 1..N by 2 do
+ yield i; // yield values instead of returning.
+ for i in 2..N by 2 do
+ yield i;
+}
+
+for i in oddsThenEvens(10) do write(i, ", ");
+writeln();
+
+// Iterators can also yield conditionally, the result of which can be nothing
+iter absolutelyNothing(N): int {
+ for i in 1..N {
+ if N < i { // Always false
+ yield i; // Yield statement never happens
+ }
+ }
+}
+
+for i in absolutelyNothing(10) {
+ writeln("Woa there! absolutelyNothing yielded ", i);
+}
+
+// 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
+// iteration of the zipped iterator yields a tuple of one value yielded
+// from each iterator.
+for (positive, negative) in zip(1..5, -5..-1) do
+ writeln((positive, negative));
+
+// Zipper iteration is quite important in the assignment of arrays,
+// slices of arrays, and array/loop expressions.
+var fromThatArray : [1..#5] int = [1,2,3,4,5];
+var toThisArray : [100..#5] int;
+
+// Some zipper operations implement other operations.
+// The first statement and the loop are equivalent.
+toThisArray = fromThatArray;
+for (i,j) in zip(toThisArray.domain, fromThatArray.domain) {
+ toThisArray[i] = fromThatArray[j];
+}
+
+// These two chunks are also equivalent.
+toThisArray = [j in -100..#5] j;
+writeln(toThisArray);
+
+for (i, j) in zip(toThisArray.domain, -100..#5) {
+ toThisArray[i] = j;
+}
+writeln(toThisArray);
+
+// This is very important in understanding why this statement exhibits a
+// runtime error.
+
+/*
+ var iterArray : [1..10] int = [i in 1..10] if (i % 2 == 1) then i;
+*/
+
+// Even though the domain of the array and the loop-expression are
+// the same size, the body of the expression can be thought of as an iterator.
+// 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.
+
+// Classes
+
+// Classes are similar to those in C++ and Java, allocated on the heap.
+class MyClass {
+
+// Member variables
+ var memberInt : int;
+ var memberBool : bool = true;
+
+// Explicitly defined initializer.
+// We also get the compiler-generated initializer, with one argument per field.
+// Note that soon there will be no compiler-generated initializer when we
+// define any initializer(s) explicitly.
+ proc MyClass(val : real) {
+ this.memberInt = ceil(val): int;
+ }
+
+// Explicitly defined deinitializer.
+// If we did not write one, we would get the compiler-generated deinitializer,
+// which has an empty body.
+ proc deinit() {
+ writeln("MyClass deinitializer called ", (this.memberInt, this.memberBool));
+ }
+
+// Class methods.
+ proc setMemberInt(val: int) {
+ this.memberInt = val;
+ }
+
+ proc setMemberBool(val: bool) {
+ this.memberBool = val;
+ }
+
+ proc getMemberInt(): int{
+ return this.memberInt;
+ }
+
+ proc getMemberBool(): bool {
+ return this.memberBool;
+ }
+} // end MyClass
+
+// Call compiler-generated initializer, using default value for memberBool.
+var myObject = new MyClass(10);
+ myObject = new MyClass(memberInt = 10); // Equivalent
+writeln(myObject.getMemberInt());
+
+// Same, but provide a memberBool value explicitly.
+var myDiffObject = new MyClass(-1, true);
+ myDiffObject = new MyClass(memberInt = -1,
+ memberBool = true); // Equivalent
+writeln(myDiffObject);
+
+// Call the initializer we wrote.
+var myOtherObject = new MyClass(1.95);
+ myOtherObject = new MyClass(val = 1.95); // Equivalent
+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) : MyClass {
+ return new MyClass(memberInt = A.getMemberInt() + B.getMemberInt(),
+ memberBool = A.getMemberBool() || B.getMemberBool());
+}
+
+var plusObject = myObject + myDiffObject;
+writeln(plusObject);
+
+// Destruction.
+delete myObject;
+delete myDiffObject;
+delete myOtherObject;
+delete plusObject;
+
+// Classes can inherit from one or more parent classes
+class MyChildClass : MyClass {
+ var memberComplex: complex;
+}
+
+// Here's an example of generic classes.
+class GenericClass {
+ type classType;
+ var classDomain: domain(1);
+ var classArray: [classDomain] classType;
+
+// Explicit constructor.
+ proc GenericClass(type classType, elements : int) {
+ this.classDomain = {1..#elements};
+ }
+
+// Copy constructor.
+// Note: We still have to put the type as an argument, but we can
+// default to the type of the other object using the query (?) operator.
+// Further, we can take advantage of this to allow our copy constructor
+// to copy classes of different types and cast on the fly.
+ proc GenericClass(other : GenericClass(?otherType),
+ type classType = otherType) {
+ this.classDomain = other.classDomain;
+ // Copy and cast
+ for idx in this.classDomain do this[idx] = other[idx] : classType;
+ }
+
+// Define bracket notation on a GenericClass
+// object so it can behave like a normal array
+// i.e. objVar[i] or objVar(i)
+ proc this(i : int) ref : classType {
+ return this.classArray[i];
+ }
+
+// Define an implicit iterator for the class
+// to yield values from the array to a loop
+// i.e. for i in objVar do ...
+ iter these() ref : classType {
+ for i in this.classDomain do
+ yield this[i];
+ }
+} // end GenericClass
+
+// We can assign to the member array of the object using the bracket
+// notation that we defined.
+var realList = new GenericClass(real, 10);
+for i in realList.classDomain do realList[i] = i + 1.0;
+
+// We can iterate over the values in our list with the iterator
+// we defined.
+for value in realList do write(value, ", ");
+writeln();
+
+// Make a copy of realList using the copy constructor.
+var copyList = new GenericClass(realList);
+for value in copyList do write(value, ", ");
+writeln();
+
+// Make a copy of realList and change the type, also using the copy constructor.
+var copyNewTypeList = new GenericClass(realList, int);
+for value in copyNewTypeList do write(value, ", ");
+writeln();
+
+
+// Modules
+
+// Modules are Chapel's way of managing name spaces.
+// The files containing these modules do not need to be named after the modules
+// (as in Java), but files implicitly name modules.
+// For example, this file implicitly names the learnChapelInYMinutes module
+
+module OurModule {
+
+// We can use modules inside of other modules.
+// Time is one of the standard modules.
+ use Time;
+
+// We'll use this procedure in the parallelism section.
+ proc countdown(seconds: int) {
+ for i in 1..seconds by -1 {
+ writeln(i);
+ sleep(1);
+ }
+ }
+
+// It is possible to create arbitrarily deep module nests.
+// i.e. submodules of OurModule
+ module ChildModule {
+ proc foo() {
+ writeln("ChildModule.foo()");
+ }
+ }
+
+ module SiblingModule {
+ proc foo() {
+ writeln("SiblingModule.foo()");
+ }
+ }
+} // end OurModule
+
+// Using OurModule also uses all the modules it uses.
+// Since OurModule uses Time, we also use Time.
+use OurModule;
+
+// At this point we have not used ChildModule or SiblingModule so
+// their symbols (i.e. foo) are not available to us. However, the module
+// names are available, and we can explicitly call foo() through them.
+SiblingModule.foo();
+OurModule.ChildModule.foo();
+
+// Now we use ChildModule, enabling unqualified calls.
+use ChildModule;
+foo();
+
+// Parallelism
+
+// In other languages, parallelism is typically done with
+// complicated libraries and strange class structure hierarchies.
+// Chapel has it baked right into the language.
+
+// We can declare a main procedure, but all the code above main still gets
+// executed.
+proc main() {
+ writeln("PARALLELISM START");
+
+// A begin statement will spin the body of that statement off
+// into one new task.
+// A sync statement will ensure that the progress of the main
+// task will not progress until the children have synced back up.
+
+ sync {
+ begin { // Start of new task's body
+ var a = 0;
+ for i in 1..1000 do a += 1;
+ writeln("Done: ", a);
+ } // End of new tasks body
+ writeln("spun off a task!");
+ }
+ writeln("Back together");
+
+ proc printFibb(n: int) {
+ writeln("fibonacci(",n,") = ", fibonacci(n));
+ }
+
+// 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
+// order.
+ cobegin {
+ printFibb(20); // new task
+ printFibb(10); // new task
+ printFibb(5); // new task
+ {
+ // This is a nested statement body and thus is a single statement
+ // to the parent statement, executed by a single task.
+ writeln("this gets");
+ writeln("executed as");
+ writeln("a whole");
+ }
+ }
+
+// A coforall loop will create a new task for EACH iteration.
+// Again we see that prints happen in any order.
+// NOTE: coforall should be used only for creating tasks!
+// Using it to iterating over a structure is very a bad idea!
+ var num_tasks = 10; // Number of tasks we want
+ coforall taskID in 1..#num_tasks {
+ writeln("Hello from task# ", taskID);
+ }
+
+// forall loops are another parallel loop, but only create a smaller number
+// of tasks, specifically --dataParTasksPerLocale= number of tasks.
+ forall i in 1..100 {
+ write(i, ", ");
+ }
+ writeln();
+
+// Here we see that there are sections that are in order, followed by
+// a section that would not follow (e.g. 1, 2, 3, 7, 8, 9, 4, 5, 6,).
+// This is because each task is taking on a chunk of the range 1..10
+// (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
+
+// For both the forall and coforall loops, the execution of the
+// parent task will not continue until all the children sync up.
+
+// forall loops are particularly useful for parallel iteration over arrays.
+// Lets run an experiment to see how much faster a parallel loop is
+ use Time; // Import the Time module to use Timer objects
+ var timer: Timer;
+ var myBigArray: [{1..4000,1..4000}] real; // Large array we will write into
+
+// Serial Experiment:
+ timer.start(); // Start timer
+ for (x,y) in myBigArray.domain { // Serial iteration
+ myBigArray[x,y] = (x:real) / (y:real);
+ }
+ timer.stop(); // Stop timer
+ writeln("Serial: ", timer.elapsed()); // Print elapsed time
+ timer.clear(); // Clear timer for parallel loop
+
+// Parallel Experiment:
+ timer.start(); // start timer
+ forall (x,y) in myBigArray.domain { // Parallel iteration
+ myBigArray[x,y] = (x:real) / (y:real);
+ }
+ timer.stop(); // Stop timer
+ writeln("Parallel: ", timer.elapsed()); // Print elapsed time
+ timer.clear();
+
+// You may have noticed that (depending on how many cores you have)
+// the parallel loop went faster than the serial loop.
+
+// The bracket style loop-expression described
+// much earlier implicitly uses a forall loop.
+ [val in myBigArray] val = 1 / val; // Parallel operation
+
+// Atomic variables, common to many languages, are ones whose operations
+// occur uninterrupted. Multiple threads can therefore modify atomic
+// variables and can know that their values are safe.
+// Chapel atomic variables can be of type bool, int,
+// uint, and real.
+ var uranium: atomic int;
+ uranium.write(238); // atomically write a variable
+ writeln(uranium.read()); // atomically read a variable
+
+// Atomic operations are described as functions, so you can define your own.
+ uranium.sub(3); // atomically subtract a variable
+ writeln(uranium.read());
+
+ var replaceWith = 239;
+ var was = uranium.exchange(replaceWith);
+ writeln("uranium was ", was, " but is now ", replaceWith);
+
+ var isEqualTo = 235;
+ if uranium.compareExchange(isEqualTo, replaceWith) {
+ writeln("uranium was equal to ", isEqualTo,
+ " so replaced value with ", replaceWith);
+ } else {
+ writeln("uranium was not equal to ", isEqualTo,
+ " so value stays the same... whatever it was");
+ }
+
+ sync {
+ begin { // Reader task
+ writeln("Reader: waiting for uranium to be ", isEqualTo);
+ uranium.waitFor(isEqualTo);
+ writeln("Reader: uranium was set (by someone) to ", isEqualTo);
+ }
+
+ begin { // Writer task
+ writeln("Writer: will set uranium to the value ", isEqualTo, " in...");
+ countdown(3);
+ uranium.write(isEqualTo);
+ }
+ }
+
+// sync variables have two states: empty and full.
+// If you read an empty variable or write a full variable, you are waited
+// until the variable is full or empty again.
+ var someSyncVar$: sync int; // varName$ is a convention not a law.
+ sync {
+ begin { // Reader task
+ writeln("Reader: waiting to read.");
+ var read_sync = someSyncVar$;
+ writeln("Reader: value is ", read_sync);
+ }
+
+ begin { // Writer task
+ writeln("Writer: will write in...");
+ countdown(3);
+ someSyncVar$ = 123;
+ }
+ }
+
+// 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
+// indefinitely.
+ var someSingleVar$: single int; // varName$ is a convention not a law.
+ sync {
+ begin { // Reader task
+ writeln("Reader: waiting to read.");
+ for i in 1..5 {
+ var read_single = someSingleVar$;
+ writeln("Reader: iteration ", i,", and the value is ", read_single);
+ }
+ }
+
+ begin { // Writer task
+ writeln("Writer: will write in...");
+ countdown(3);
+ someSingleVar$ = 5; // first and only write ever.
+ }
+ }
+
+// Here's an example using atomics and a sync variable to create a
+// count-down mutex (also known as a multiplexer).
+ var count: atomic int; // our counter
+ var lock$: sync bool; // the mutex lock
+
+ count.write(2); // Only let two tasks in at a time.
+ lock$.writeXF(true); // Set lock$ to full (unlocked)
+ // Note: The value doesn't actually matter, just the state
+ // (full:unlocked / empty:locked)
+ // Also, writeXF() fills (F) the sync var regardless of its state (X)
+
+ coforall task in 1..#5 { // Generate tasks
+ // Create a barrier
+ do {
+ lock$; // Read lock$ (wait)
+ } while (count.read() < 1); // Keep waiting until a spot opens up
+
+ count.sub(1); // decrement the counter
+ lock$.writeXF(true); // Set lock$ to full (signal)
+
+ // Actual 'work'
+ writeln("Task #", task, " doing work.");
+ sleep(2);
+
+ count.add(1); // Increment the counter
+ lock$.writeXF(true); // Set lock$ to full (signal)
+ }
+
+// We can define the operations + * & | ^ && || min max minloc maxloc
+// over an entire array using scans and reductions.
+// Reductions apply the operation over the entire array and
+// result in a scalar value.
+ var listOfValues: [1..10] int = [15,57,354,36,45,15,456,8,678,2];
+ var sumOfValues = + reduce listOfValues;
+ var maxValue = max reduce listOfValues; // 'max' give just 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.
+ var (theMaxValue, idxOfMax) = maxloc reduce zip(listOfValues,
+ listOfValues.domain);
+
+ writeln((sumOfValues, maxValue, idxOfMax, listOfValues[idxOfMax]));
+
+// Scans apply the operation incrementally and return an array with the
+// values of the operation at that index as it progressed through the
+// array from array.domain.low to array.domain.high.
+ var runningSumOfValues = + scan listOfValues;
+ var maxScan = max scan listOfValues;
+ writeln(runningSumOfValues);
+ writeln(maxScan);
+} // end main()
+```
+
+Who is this tutorial for?
+-------------------------
+
+This tutorial is for people who want to learn the ropes of chapel without
+having to hear about what fiber mixture the ropes are, or how they were
+braided, or how the braid configurations differ between one another. It won't
+teach you how to develop amazingly performant code, and it's not exhaustive.
+Refer to the [language specification](https://chapel-lang.org/docs/latest/language/spec.html) and
+the [module documentation](https://chapel-lang.org/docs/latest/) for more
+details.
+
+Occasionally check back here and on the [Chapel site](https://chapel-lang.org)
+to see if more topics have been added or more tutorials created.
+
+### What this tutorial is lacking:
+
+ * Exposition of the [standard modules](https://chapel-lang.org/docs/latest/modules/standard.html)
+ * Multiple Locales (distributed memory system)
+ * Records
+ * Parallel iterators
+
+Your input, questions, and discoveries are important to the developers!
+-----------------------------------------------------------------------
+
+The Chapel language is still in-development (version 1.16.0), so there are
+occasional hiccups with performance and language features. The more information
+you give the Chapel development team about issues you encounter or features you
+would like to see, the better the language becomes. Feel free to email the team
+and other developers through the [sourceforge email lists](https://sourceforge.net/p/chapel/mailman).
+
+If you're really interested in the development of the compiler or contributing
+to the project, [check out the master GitHub repository](https://github.com/chapel-lang/chapel).
+It is under the [Apache 2.0 License](http://www.apache.org/licenses/LICENSE-2.0).
+
+Installing the Compiler
+-----------------------
+
+Chapel can be built and installed on your average 'nix machine (and cygwin).
+[Download the latest release version](https://github.com/chapel-lang/chapel/releases/)
+and it's as easy as
+
+ 1. `tar -xvf chapel-1.16.0.tar.gz`
+ 2. `cd chapel-1.16.0`
+ 3. `source util/setchplenv.bash # or .sh or .csh or .fish`
+ 4. `make`
+ 5. `make check # optional`
+
+You will need to `source util/setchplenv.EXT` from within the Chapel directory
+(`$CHPL_HOME`) every time your terminal starts so it's suggested that you drop
+that command in a script that will get executed on startup (like .bashrc).
+
+Chapel is easily installed with Brew for OS X
+
+ 1. `brew update`
+ 2. `brew install chapel`
+
+Compiling Code
+--------------
+
+Builds like other compilers:
+
+`chpl myFile.chpl -o myExe`
+
+Notable arguments:
+
+ * `--fast`: enables a number of optimizations and disables array bounds
+ checks. Should only enable when application is stable.
+ * `--set <Symbol Name>=<Value>`: set config param `<Symbol Name>` to `<Value>`
+ at compile-time.
+ * `--main-module <Module Name>`: use the main() procedure found in the module
+ `<Module Name>` as the executable's main.
+ * `--module-dir <Directory>`: includes `<Directory>` in the module search path.