2015-07-13 02:17:23 +03:00
|
|
|
|
---
|
2024-10-21 00:46:35 +03:00
|
|
|
|
language: Chapel
|
2015-07-20 02:01:04 +03:00
|
|
|
|
filename: learnchapel.chpl
|
2015-07-13 02:17:23 +03:00
|
|
|
|
contributors:
|
2017-11-02 22:22:33 +03:00
|
|
|
|
- ["Ian J. Bertolacci", "https://www.cs.arizona.edu/~ianbertolacci/"]
|
|
|
|
|
- ["Ben Harshbarger", "https://github.com/benharsh/"]
|
2015-07-13 02:17:23 +03:00
|
|
|
|
---
|
2015-07-15 03:44:55 +03:00
|
|
|
|
|
2017-11-02 22:22:33 +03:00
|
|
|
|
You can read all about Chapel at [Cray's official Chapel website](https://chapel-lang.org).
|
2017-04-03 22:29:17 +03:00
|
|
|
|
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.
|
2015-07-13 02:17:23 +03:00
|
|
|
|
|
2015-07-15 03:44:55 +03:00
|
|
|
|
More information and support can be found at the bottom of this document.
|
2015-07-13 02:17:23 +03:00
|
|
|
|
|
2024-05-13 22:28:48 +03:00
|
|
|
|
You can refer to the official site for [latest version](https://chapel-lang.org/docs/master/primers/learnChapelInYMinutes.html) of this document.
|
|
|
|
|
|
2017-01-01 02:25:24 +03:00
|
|
|
|
```chapel
|
2024-05-13 22:28:48 +03:00
|
|
|
|
/*
|
|
|
|
|
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
|
|
|
|
|
*/
|
|
|
|
|
|
2015-07-13 02:17:23 +03:00
|
|
|
|
// Comments are C-family style
|
2017-04-03 22:29:17 +03:00
|
|
|
|
|
2015-07-13 02:17:23 +03:00
|
|
|
|
// one line comment
|
|
|
|
|
/*
|
2024-05-13 22:28:48 +03:00
|
|
|
|
multi-line comment
|
2015-07-13 02:17:23 +03:00
|
|
|
|
*/
|
|
|
|
|
|
2024-05-13 22:28:48 +03:00
|
|
|
|
/*
|
|
|
|
|
Basic printing
|
|
|
|
|
*/
|
2017-04-03 22:29:17 +03:00
|
|
|
|
|
|
|
|
|
write("Hello, ");
|
|
|
|
|
writeln("World!");
|
|
|
|
|
|
2024-05-13 22:28:48 +03:00
|
|
|
|
// ``write`` and ``writeln`` can take a list of things to print.
|
2017-04-03 22:29:17 +03:00
|
|
|
|
// 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:
|
2024-05-13 22:28:48 +03:00
|
|
|
|
use IO; // Required for accessing the alternative output channels
|
|
|
|
|
|
2017-04-03 22:29:17 +03:00
|
|
|
|
stdout.writeln("This goes to standard output, just like plain writeln() does");
|
|
|
|
|
stderr.writeln("This goes to standard error");
|
|
|
|
|
|
2024-05-13 22:28:48 +03:00
|
|
|
|
/*
|
|
|
|
|
Variables
|
|
|
|
|
*/
|
2015-07-13 02:17:23 +03:00
|
|
|
|
|
2015-10-02 19:31:25 +03:00
|
|
|
|
// Variables don't have to be explicitly typed as long as
|
2015-07-15 03:30:09 +03:00
|
|
|
|
// the compiler can figure out the type that it will hold.
|
2024-05-13 22:28:48 +03:00
|
|
|
|
// 10 is an ``int``, so ``myVar`` is implicitly an ``int``
|
2017-04-03 22:29:17 +03:00
|
|
|
|
var myVar = 10;
|
2015-07-13 02:17:23 +03:00
|
|
|
|
myVar = -10;
|
2015-07-15 05:07:59 +03:00
|
|
|
|
var mySecondVar = myVar;
|
2024-05-13 22:28:48 +03:00
|
|
|
|
// ``var anError;`` would be a compile-time error.
|
2015-07-13 02:17:23 +03:00
|
|
|
|
|
2017-04-03 22:29:17 +03:00
|
|
|
|
// We can (and should) explicitly type things.
|
2015-07-20 22:59:35 +03:00
|
|
|
|
var myThirdVar: real;
|
2015-07-15 05:07:59 +03:00
|
|
|
|
var myFourthVar: real = -1.234;
|
|
|
|
|
myThirdVar = myFourthVar;
|
2015-07-13 02:17:23 +03:00
|
|
|
|
|
2024-05-13 22:28:48 +03:00
|
|
|
|
/*
|
|
|
|
|
Types
|
|
|
|
|
*/
|
2017-04-03 22:29:17 +03:00
|
|
|
|
|
2015-07-13 02:17:23 +03:00
|
|
|
|
// There are a number of basic types.
|
2015-07-15 05:07:59 +03:00
|
|
|
|
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
|
2017-04-03 22:29:17 +03:00
|
|
|
|
myCplx = myInt + myImag; // Another way to form complex numbers
|
2015-07-15 05:07:59 +03:00
|
|
|
|
var myBool: bool = false; // Booleans
|
|
|
|
|
var myStr: string = "Some string..."; // Strings
|
2017-04-03 22:29:17 +03:00
|
|
|
|
var singleQuoteStr = 'Another string...'; // String literal with single quotes
|
2015-07-13 02:17:23 +03:00
|
|
|
|
|
2017-04-03 22:29:17 +03:00
|
|
|
|
// Some types can have sizes.
|
2015-07-13 02:17:23 +03:00
|
|
|
|
var my8Int: int(8) = 10; // 8 bit (one byte) sized int;
|
|
|
|
|
var my64Real: real(64) = 1.516; // 64 bit (8 bytes) sized real
|
|
|
|
|
|
2017-04-03 22:29:17 +03:00
|
|
|
|
// Typecasting.
|
2015-07-13 02:17:23 +03:00
|
|
|
|
var intFromReal = myReal : int;
|
2015-07-15 03:30:09 +03:00
|
|
|
|
var intFromReal2: int = myReal : int;
|
|
|
|
|
|
2017-04-03 22:29:17 +03:00
|
|
|
|
// 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);
|
|
|
|
|
|
2024-05-13 22:28:48 +03:00
|
|
|
|
/*
|
|
|
|
|
Constants and Parameters
|
|
|
|
|
*/
|
2017-04-03 22:29:17 +03:00
|
|
|
|
|
2024-05-13 22:28:48 +03:00
|
|
|
|
// A ``const`` is a constant, and cannot be changed after set in runtime.
|
2015-07-15 03:32:00 +03:00
|
|
|
|
const almostPi: real = 22.0/7.0;
|
2015-07-15 05:07:59 +03:00
|
|
|
|
|
2024-05-13 22:28:48 +03:00
|
|
|
|
// A ``param`` is a constant whose value must be known statically at
|
2017-04-03 22:29:17 +03:00
|
|
|
|
// compile-time.
|
2015-07-15 03:30:09 +03:00
|
|
|
|
param compileTimeConst: int = 16;
|
|
|
|
|
|
2024-05-13 22:28:48 +03:00
|
|
|
|
// The ``config`` modifier allows values to be set at the command line.
|
|
|
|
|
// Set with ``--varCmdLineArg=Value`` or ``--varCmdLineArg Value`` at runtime.
|
2015-10-02 19:31:25 +03:00
|
|
|
|
config var varCmdLineArg: int = -123;
|
2015-07-15 03:30:09 +03:00
|
|
|
|
config const constCmdLineArg: int = 777;
|
|
|
|
|
|
2024-05-13 22:28:48 +03:00
|
|
|
|
// ``config param`` can be set at compile-time.
|
|
|
|
|
// Set with ``--set paramCmdLineArg=value`` at compile-time.
|
2015-07-15 03:30:09 +03:00
|
|
|
|
config param paramCmdLineArg: bool = false;
|
2017-04-03 22:29:17 +03:00
|
|
|
|
writeln(varCmdLineArg, ", ", constCmdLineArg, ", ", paramCmdLineArg);
|
2015-07-13 02:17:23 +03:00
|
|
|
|
|
2024-05-13 22:28:48 +03:00
|
|
|
|
/*
|
|
|
|
|
References
|
|
|
|
|
*/
|
2017-04-03 22:29:17 +03:00
|
|
|
|
|
2024-05-13 22:28:48 +03:00
|
|
|
|
// ``ref`` operates much like a reference in C++. In Chapel, a ``ref`` cannot
|
2017-04-03 22:29:17 +03:00
|
|
|
|
// be made to alias a variable other than the variable it is initialized with.
|
2024-05-13 22:28:48 +03:00
|
|
|
|
// Here, ``refToActual`` refers to ``actual``.
|
2015-07-15 22:08:15 +03:00
|
|
|
|
var actual = 10;
|
2024-05-13 22:28:48 +03:00
|
|
|
|
ref refToActual = actual;
|
2017-04-03 22:29:17 +03:00
|
|
|
|
writeln(actual, " == ", refToActual); // prints the same value
|
2015-07-15 22:08:15 +03:00
|
|
|
|
actual = -123; // modify actual (which refToActual refers to)
|
2017-04-03 22:29:17 +03:00
|
|
|
|
writeln(actual, " == ", refToActual); // prints the same value
|
2015-07-15 22:08:15 +03:00
|
|
|
|
refToActual = 99999999; // modify what refToActual refers to (which is actual)
|
2017-04-03 22:29:17 +03:00
|
|
|
|
writeln(actual, " == ", refToActual); // prints the same value
|
|
|
|
|
|
2024-05-13 22:28:48 +03:00
|
|
|
|
/*
|
|
|
|
|
Operators
|
|
|
|
|
*/
|
2015-07-15 22:08:15 +03:00
|
|
|
|
|
2017-04-03 22:29:17 +03:00
|
|
|
|
// Math operators:
|
2015-07-13 02:17:23 +03:00
|
|
|
|
var a: int, thisInt = 1234, thatInt = 5678;
|
|
|
|
|
a = thisInt + thatInt; // Addition
|
|
|
|
|
a = thisInt * thatInt; // Multiplication
|
|
|
|
|
a = thisInt - thatInt; // Subtraction
|
2015-07-15 05:07:59 +03:00
|
|
|
|
a = thisInt / thatInt; // Division
|
|
|
|
|
a = thisInt ** thatInt; // Exponentiation
|
|
|
|
|
a = thisInt % thatInt; // Remainder (modulo)
|
2015-07-13 02:17:23 +03:00
|
|
|
|
|
2017-04-03 22:29:17 +03:00
|
|
|
|
// Logical operators:
|
2015-07-13 02:17:23 +03:00
|
|
|
|
var b: bool, thisBool = false, thatBool = true;
|
2015-07-15 05:07:59 +03:00
|
|
|
|
b = thisBool && thatBool; // Logical and
|
|
|
|
|
b = thisBool || thatBool; // Logical or
|
|
|
|
|
b = !thisBool; // Logical negation
|
2015-07-13 02:17:23 +03:00
|
|
|
|
|
2017-04-03 22:29:17 +03:00
|
|
|
|
// Relational operators:
|
2015-07-15 05:07:59 +03:00
|
|
|
|
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
|
2015-07-13 02:17:23 +03:00
|
|
|
|
|
2017-04-03 22:29:17 +03:00
|
|
|
|
// Bitwise operators:
|
2015-07-15 05:07:59 +03:00
|
|
|
|
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
|
2015-07-13 02:17:23 +03:00
|
|
|
|
|
2017-04-03 22:29:17 +03:00
|
|
|
|
// 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:
|
|
|
|
|
//
|
2024-05-13 22:28:48 +03:00
|
|
|
|
// ``++j``, ``--j``, ``j++``, ``j--``
|
2017-04-03 22:29:17 +03:00
|
|
|
|
|
|
|
|
|
// Swap operator:
|
2015-07-15 03:30:09 +03:00
|
|
|
|
var old_this = thisInt;
|
|
|
|
|
var old_that = thatInt;
|
2015-07-13 02:17:23 +03:00
|
|
|
|
thisInt <=> thatInt; // Swap the values of thisInt and thatInt
|
2017-04-03 22:29:17 +03:00
|
|
|
|
writeln((old_this == thatInt) && (old_that == thisInt));
|
|
|
|
|
|
|
|
|
|
// Operator overloads can also be defined, as we'll see with procedures.
|
2015-07-13 02:17:23 +03:00
|
|
|
|
|
2024-05-13 22:28:48 +03:00
|
|
|
|
/*
|
|
|
|
|
Tuples
|
|
|
|
|
*/
|
2015-07-13 02:17:23 +03:00
|
|
|
|
|
2017-04-03 22:29:17 +03:00
|
|
|
|
// Tuples can be of the same type or different types.
|
|
|
|
|
var sameTup: 2*int = (10, -1);
|
2015-07-15 04:40:53 +03:00
|
|
|
|
var sameTup2 = (11, -6);
|
2015-07-13 02:17:23 +03:00
|
|
|
|
var diffTup: (int,real,complex) = (5, 1.928, myCplx);
|
2017-04-03 22:29:17 +03:00
|
|
|
|
var diffTupe2 = (7, 5.64, 6.0+1.5i);
|
2015-07-15 05:07:59 +03:00
|
|
|
|
|
2017-04-03 22:29:17 +03:00
|
|
|
|
// Tuples can be accessed using square brackets or parentheses, and are
|
|
|
|
|
// 1-indexed.
|
|
|
|
|
writeln("(", sameTup[1], ",", sameTup(2), ")");
|
|
|
|
|
writeln(diffTup);
|
2015-07-15 05:07:59 +03:00
|
|
|
|
|
2015-07-13 02:17:23 +03:00
|
|
|
|
// Tuples can also be written into.
|
2017-04-03 22:29:17 +03:00
|
|
|
|
diffTup(1) = -1;
|
2015-07-15 05:07:59 +03:00
|
|
|
|
|
2017-04-03 22:29:17 +03:00
|
|
|
|
// Tuple values can be expanded into their own variables.
|
2015-07-14 17:40:53 +03:00
|
|
|
|
var (tupInt, tupReal, tupCplx) = diffTup;
|
2017-04-03 22:29:17 +03:00
|
|
|
|
writeln(diffTup == (tupInt, tupReal, tupCplx));
|
2015-07-15 05:07:59 +03:00
|
|
|
|
|
2017-04-03 22:29:17 +03:00
|
|
|
|
// They are also useful for writing a list of variables, as is common in debugging.
|
|
|
|
|
writeln((a,b,thisInt,thatInt,thisBool,thatBool));
|
2015-07-13 02:17:23 +03:00
|
|
|
|
|
2024-05-13 22:28:48 +03:00
|
|
|
|
/*
|
|
|
|
|
Control Flow
|
|
|
|
|
*/
|
2015-07-13 02:17:23 +03:00
|
|
|
|
|
2024-05-13 22:28:48 +03:00
|
|
|
|
// ``if`` - ``then`` - ``else`` works just like any other C-family language.
|
2015-07-13 02:17:23 +03:00
|
|
|
|
if 10 < 100 then
|
2017-04-03 22:29:17 +03:00
|
|
|
|
writeln("All is well");
|
2015-07-13 02:17:23 +03:00
|
|
|
|
|
|
|
|
|
if -1 < 1 then
|
2017-04-03 22:29:17 +03:00
|
|
|
|
writeln("Continuing to believe reality");
|
2015-07-13 02:17:23 +03:00
|
|
|
|
else
|
2024-05-13 22:28:48 +03:00
|
|
|
|
writeln("Send mathematician, something's wrong");
|
2015-07-13 02:17:23 +03:00
|
|
|
|
|
2017-04-03 22:29:17 +03:00
|
|
|
|
// You can use parentheses if you prefer.
|
|
|
|
|
if (10 > 100) {
|
|
|
|
|
writeln("Universe broken. Please reboot universe.");
|
2015-07-13 02:17:23 +03:00
|
|
|
|
}
|
|
|
|
|
|
2017-04-03 22:29:17 +03:00
|
|
|
|
if a % 2 == 0 {
|
|
|
|
|
writeln(a, " is even.");
|
2015-07-13 02:17:23 +03:00
|
|
|
|
} else {
|
2017-04-03 22:29:17 +03:00
|
|
|
|
writeln(a, " is odd.");
|
2015-07-13 02:17:23 +03:00
|
|
|
|
}
|
|
|
|
|
|
2017-04-03 22:29:17 +03:00
|
|
|
|
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.");
|
2015-07-13 02:17:23 +03:00
|
|
|
|
} else {
|
2017-04-03 22:29:17 +03:00
|
|
|
|
writeln(b, " is divided by 3 with a remainder of 2.");
|
2015-07-13 02:17:23 +03:00
|
|
|
|
}
|
|
|
|
|
|
2024-05-13 22:28:48 +03:00
|
|
|
|
// Ternary: ``if`` - ``then`` - ``else`` in a statement.
|
2017-04-03 22:29:17 +03:00
|
|
|
|
var maximum = if thisInt < thatInt then thatInt else thisInt;
|
2015-07-13 02:17:23 +03:00
|
|
|
|
|
2024-05-13 22:28:48 +03:00
|
|
|
|
// ``select`` statements are much like switch statements in other languages.
|
|
|
|
|
// However, ``select`` statements don't cascade like in C or Java.
|
2015-07-13 02:17:23 +03:00
|
|
|
|
var inputOption = "anOption";
|
2017-04-03 22:29:17 +03:00
|
|
|
|
select inputOption {
|
|
|
|
|
when "anOption" do writeln("Chose 'anOption'");
|
2015-07-13 02:17:23 +03:00
|
|
|
|
when "otherOption" {
|
2017-04-03 22:29:17 +03:00
|
|
|
|
writeln("Chose 'otherOption'");
|
|
|
|
|
writeln("Which has a body");
|
2015-07-13 02:17:23 +03:00
|
|
|
|
}
|
2015-10-02 19:31:25 +03:00
|
|
|
|
otherwise {
|
2017-04-03 22:29:17 +03:00
|
|
|
|
writeln("Any other Input");
|
2024-05-13 22:28:48 +03:00
|
|
|
|
writeln("the otherwise case doesn't need a do if the body is one line");
|
2015-07-13 02:17:23 +03:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-13 22:28:48 +03:00
|
|
|
|
// ``while`` and ``do``-``while`` loops also behave like their C counterparts.
|
2015-07-13 02:17:23 +03:00
|
|
|
|
var j: int = 1;
|
|
|
|
|
var jSum: int = 0;
|
2017-04-03 22:29:17 +03:00
|
|
|
|
while (j <= 1000) {
|
2015-07-13 02:17:23 +03:00
|
|
|
|
jSum += j;
|
2015-07-15 05:07:59 +03:00
|
|
|
|
j += 1;
|
2015-07-13 02:17:23 +03:00
|
|
|
|
}
|
2017-04-03 22:29:17 +03:00
|
|
|
|
writeln(jSum);
|
2015-07-13 02:17:23 +03:00
|
|
|
|
|
2017-04-03 22:29:17 +03:00
|
|
|
|
do {
|
2015-07-13 02:17:23 +03:00
|
|
|
|
jSum += j;
|
|
|
|
|
j += 1;
|
2017-04-03 22:29:17 +03:00
|
|
|
|
} while (j <= 10000);
|
|
|
|
|
writeln(jSum);
|
2015-07-13 02:17:23 +03:00
|
|
|
|
|
2024-05-13 22:28:48 +03:00
|
|
|
|
// ``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
|
2017-04-03 22:29:17 +03:00
|
|
|
|
// in Chapel, and as such can be stored in variables.
|
|
|
|
|
for i in 1..10 do write(i, ", ");
|
|
|
|
|
writeln();
|
2015-07-13 02:17:23 +03:00
|
|
|
|
|
|
|
|
|
var iSum: int = 0;
|
|
|
|
|
for i in 1..1000 {
|
|
|
|
|
iSum += i;
|
|
|
|
|
}
|
2017-04-03 22:29:17 +03:00
|
|
|
|
writeln(iSum);
|
2015-07-13 02:17:23 +03:00
|
|
|
|
|
|
|
|
|
for x in 1..10 {
|
|
|
|
|
for y in 1..10 {
|
2017-04-03 22:29:17 +03:00
|
|
|
|
write((x,y), "\t");
|
2015-07-13 02:17:23 +03:00
|
|
|
|
}
|
2017-04-03 22:29:17 +03:00
|
|
|
|
writeln();
|
2015-07-13 02:17:23 +03:00
|
|
|
|
}
|
|
|
|
|
|
2024-05-13 22:28:48 +03:00
|
|
|
|
/*
|
|
|
|
|
Ranges and Domains
|
|
|
|
|
*/
|
2017-04-03 22:29:17 +03:00
|
|
|
|
|
|
|
|
|
// 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.
|
2015-07-15 04:40:53 +03:00
|
|
|
|
var range1to10: range = 1..10; // 1, 2, 3, ..., 10
|
2015-07-15 03:30:09 +03:00
|
|
|
|
var range2to11 = 2..11; // 2, 3, 4, ..., 11
|
2017-04-03 22:29:17 +03:00
|
|
|
|
var rangeThisToThat: range = thisInt..thatInt; // using variables
|
|
|
|
|
var rangeEmpty: range = 100..-100; // this is valid but contains no indices
|
2015-07-15 03:30:09 +03:00
|
|
|
|
|
2017-04-03 22:29:17 +03:00
|
|
|
|
// 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
|
2015-07-13 02:17:23 +03:00
|
|
|
|
|
2024-05-13 22:28:48 +03:00
|
|
|
|
// Ranges can be strided (and reversed) using the ``by`` operator.
|
2015-07-13 02:17:23 +03:00
|
|
|
|
var range2to10by2: range(stridable=true) = 2..10 by 2; // 2, 4, 6, 8, 10
|
2017-04-03 22:29:17 +03:00
|
|
|
|
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
|
2024-05-13 22:28:48 +03:00
|
|
|
|
writeln("Size of range '", trapRange, "' = ", trapRange.size);
|
2015-07-13 02:17:23 +03:00
|
|
|
|
|
2024-05-13 22:28:48 +03:00
|
|
|
|
// Note: ``range(boundedType= ...)`` and ``range(stridable= ...)`` are only
|
2017-04-03 22:29:17 +03:00
|
|
|
|
// necessary if we explicitly type the variable.
|
2015-07-15 04:40:53 +03:00
|
|
|
|
|
2024-05-13 22:28:48 +03:00
|
|
|
|
// The end point of a range can be computed by specifying the total size
|
|
|
|
|
// of the range using the count (``#``) operator.
|
2015-07-13 02:17:23 +03:00
|
|
|
|
var rangeCount: range = -5..#12; // range from -5 to 6
|
|
|
|
|
|
2017-04-03 22:29:17 +03:00
|
|
|
|
// Operators can be mixed.
|
2015-07-13 02:17:23 +03:00
|
|
|
|
var rangeCountBy: range(stridable=true) = -5..#12 by 2; // -5, -3, -1, 1, 3, 5
|
2017-04-03 22:29:17 +03:00
|
|
|
|
writeln(rangeCountBy);
|
2015-07-13 02:17:23 +03:00
|
|
|
|
|
2017-04-03 22:29:17 +03:00
|
|
|
|
// 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.
|
2024-05-13 22:28:48 +03:00
|
|
|
|
writeln((rangeCountBy.first, rangeCountBy.last, rangeCountBy.size,
|
|
|
|
|
rangeCountBy.stride, rangeCountBy.contains(2)));
|
2015-07-13 02:17:23 +03:00
|
|
|
|
|
2017-04-03 22:29:17 +03:00
|
|
|
|
for i in rangeCountBy {
|
|
|
|
|
write(i, if i == rangeCountBy.last then "\n" else ", ");
|
2015-07-13 02:17:23 +03:00
|
|
|
|
}
|
|
|
|
|
|
2017-04-03 22:29:17 +03:00
|
|
|
|
// Rectangular domains are defined using the same range syntax,
|
|
|
|
|
// but they are required to be bounded (unlike ranges).
|
2015-07-15 03:30:09 +03:00
|
|
|
|
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
|
2015-07-13 02:17:23 +03:00
|
|
|
|
|
2017-04-03 22:29:17 +03:00
|
|
|
|
// 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.
|
2015-07-13 02:17:23 +03:00
|
|
|
|
for idx in twoDimensions do
|
2017-04-03 22:29:17 +03:00
|
|
|
|
write(idx, ", ");
|
|
|
|
|
writeln();
|
2015-07-13 02:17:23 +03:00
|
|
|
|
|
2024-05-13 22:28:48 +03:00
|
|
|
|
// These tuples can also be destructured.
|
2015-07-13 02:17:23 +03:00
|
|
|
|
for (x,y) in twoDimensions {
|
2017-04-03 22:29:17 +03:00
|
|
|
|
write("(", x, ", ", y, ")", ", ");
|
2015-07-13 02:17:23 +03:00
|
|
|
|
}
|
2017-04-03 22:29:17 +03:00
|
|
|
|
writeln();
|
2015-07-13 02:17:23 +03:00
|
|
|
|
|
2017-04-03 22:29:17 +03:00
|
|
|
|
// Associative domains act like sets.
|
2015-07-15 03:30:09 +03:00
|
|
|
|
var stringSet: domain(string); // empty set of strings
|
|
|
|
|
stringSet += "a";
|
|
|
|
|
stringSet += "b";
|
|
|
|
|
stringSet += "c";
|
2015-10-08 06:11:24 +03:00
|
|
|
|
stringSet += "a"; // Redundant add "a"
|
2015-07-15 05:07:59 +03:00
|
|
|
|
stringSet -= "c"; // Remove "c"
|
2017-04-03 22:29:17 +03:00
|
|
|
|
writeln(stringSet.sorted());
|
|
|
|
|
|
|
|
|
|
// Associative domains can also have a literal syntax
|
|
|
|
|
var intSet = {1, 2, 4, 5, 100};
|
2015-07-13 02:17:23 +03:00
|
|
|
|
|
2015-08-06 04:22:56 +03:00
|
|
|
|
// Both ranges and domains can be sliced to produce a range or domain with the
|
2017-04-03 22:29:17 +03:00
|
|
|
|
// intersection of indices.
|
2015-08-06 04:22:56 +03:00
|
|
|
|
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
|
2017-04-03 22:29:17 +03:00
|
|
|
|
writeln((rangeA, rangeB, rangeC));
|
2015-08-06 04:22:56 +03:00
|
|
|
|
|
|
|
|
|
var domainA = {1..10, 5..20};
|
|
|
|
|
var domainB = {-5..5, 1..10};
|
|
|
|
|
var domainC = domainA[domainB];
|
2017-04-03 22:29:17 +03:00
|
|
|
|
writeln((domainA, domainB, domainC));
|
|
|
|
|
|
2024-05-13 22:28:48 +03:00
|
|
|
|
/*
|
|
|
|
|
Arrays
|
|
|
|
|
*/
|
2015-08-06 04:22:56 +03:00
|
|
|
|
|
2017-04-03 22:29:17 +03:00
|
|
|
|
// Arrays are similar to those of other languages.
|
|
|
|
|
// Their sizes are defined using domains that represent their indices.
|
2015-07-15 03:30:09 +03:00
|
|
|
|
var intArray: [1..10] int;
|
2017-04-03 22:29:17 +03:00
|
|
|
|
var intArray2: [{1..10}] int; // equivalent
|
2015-07-13 02:17:23 +03:00
|
|
|
|
|
2017-04-03 22:29:17 +03:00
|
|
|
|
// They can be accessed using either brackets or parentheses
|
2015-07-13 02:17:23 +03:00
|
|
|
|
for i in 1..10 do
|
|
|
|
|
intArray[i] = -i;
|
2017-04-03 22:29:17 +03:00
|
|
|
|
writeln(intArray);
|
|
|
|
|
|
2024-05-13 22:28:48 +03:00
|
|
|
|
// 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.
|
2015-07-13 02:17:23 +03:00
|
|
|
|
var realDomain: domain(2) = {1..5,1..7};
|
|
|
|
|
var realArray: [realDomain] real;
|
2017-04-03 22:29:17 +03:00
|
|
|
|
var realArray2: [1..5,1..7] real; // equivalent
|
|
|
|
|
var realArray3: [{1..5,1..7}] real; // equivalent
|
2015-07-13 02:17:23 +03:00
|
|
|
|
|
|
|
|
|
for i in 1..5 {
|
2015-07-15 05:07:59 +03:00
|
|
|
|
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
|
2015-07-13 02:17:23 +03:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-03 22:29:17 +03:00
|
|
|
|
// Arrays have domains as members, and can be iterated over as normal.
|
2015-10-02 19:31:25 +03:00
|
|
|
|
for idx in realArray.domain { // Again, idx is a 2*int tuple
|
2017-04-03 22:29:17 +03:00
|
|
|
|
realArray[idx] = 1 / realArray[idx[1], idx[2]]; // Access by tuple and list
|
2015-07-13 02:17:23 +03:00
|
|
|
|
}
|
|
|
|
|
|
2017-04-03 22:29:17 +03:00
|
|
|
|
writeln(realArray);
|
2015-07-13 02:17:23 +03:00
|
|
|
|
|
2017-04-03 22:29:17 +03:00
|
|
|
|
// The values of an array can also be iterated directly.
|
2015-07-13 02:17:23 +03:00
|
|
|
|
var rSum: real = 0;
|
|
|
|
|
for value in realArray {
|
2015-07-15 05:07:59 +03:00
|
|
|
|
rSum += value; // Read a value
|
|
|
|
|
value = rSum; // Write a value
|
2015-07-13 02:17:23 +03:00
|
|
|
|
}
|
2017-04-03 22:29:17 +03:00
|
|
|
|
writeln(rSum, "\n", realArray);
|
2015-07-13 02:17:23 +03:00
|
|
|
|
|
2017-04-03 22:29:17 +03:00
|
|
|
|
// Associative arrays (dictionaries) can be created using associative domains.
|
2024-05-13 22:28:48 +03:00
|
|
|
|
var dictDomain: domain(string) = { "one", "two", "three"};
|
|
|
|
|
var dict: [dictDomain] int = ["one" => 1, "two" => 2, "three" => 3];
|
|
|
|
|
|
2017-04-03 22:29:17 +03:00
|
|
|
|
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;
|
2015-07-13 02:17:23 +03:00
|
|
|
|
|
2024-05-13 22:28:48 +03:00
|
|
|
|
// 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``.
|
2015-08-06 04:22:56 +03:00
|
|
|
|
|
2015-10-02 19:31:25 +03:00
|
|
|
|
thatArray = thisArray;
|
2015-08-06 04:22:56 +03:00
|
|
|
|
thatArray[1] = -1;
|
2017-04-03 22:29:17 +03:00
|
|
|
|
writeln((thisArray, thatArray));
|
2015-08-06 04:22:56 +03:00
|
|
|
|
|
2017-04-03 22:29:17 +03:00
|
|
|
|
// 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));
|
2015-08-06 04:22:56 +03:00
|
|
|
|
|
2017-04-03 22:29:17 +03:00
|
|
|
|
// Operations can also be promoted to work on arrays. 'thisPlusThat' is also
|
|
|
|
|
// an array.
|
2015-08-06 04:22:56 +03:00
|
|
|
|
var thisPlusThat = thisArray + thatArray;
|
2017-04-03 22:29:17 +03:00
|
|
|
|
writeln(thisPlusThat);
|
2015-08-06 04:22:56 +03:00
|
|
|
|
|
2017-04-03 22:29:17 +03:00
|
|
|
|
// Moving on, arrays and loops can also be expressions, where the loop
|
2024-05-13 22:28:48 +03:00
|
|
|
|
// body's expression is the result of each iteration.
|
2015-08-06 04:22:56 +03:00
|
|
|
|
var arrayFromLoop = for i in 1..10 do i;
|
2017-04-03 22:29:17 +03:00
|
|
|
|
writeln(arrayFromLoop);
|
2015-08-06 04:22:56 +03:00
|
|
|
|
|
2017-04-03 22:29:17 +03:00
|
|
|
|
// An expression can result in nothing, such as when filtering with an if-expression.
|
2015-08-06 04:22:56 +03:00
|
|
|
|
var evensOrFives = for i in 1..10 do if (i % 2 == 0 || i % 5 == 0) then i;
|
|
|
|
|
|
2017-04-03 22:29:17 +03:00
|
|
|
|
writeln(arrayFromLoop);
|
2015-08-06 04:22:56 +03:00
|
|
|
|
|
2017-04-03 22:29:17 +03:00
|
|
|
|
// Array expressions can also be written with a bracket notation.
|
2024-05-13 22:28:48 +03:00
|
|
|
|
// Note: this syntax uses the ``forall`` parallel concept discussed later.
|
2017-04-03 22:29:17 +03:00
|
|
|
|
var evensOrFivesAgain = [i in 1..10] if (i % 2 == 0 || i % 5 == 0) then i;
|
2015-08-06 04:22:56 +03:00
|
|
|
|
|
2017-04-03 22:29:17 +03:00
|
|
|
|
// They can also be written over the values of the array.
|
|
|
|
|
arrayFromLoop = [value in arrayFromLoop] value + 1;
|
2015-08-06 04:22:56 +03:00
|
|
|
|
|
|
|
|
|
|
2024-05-13 22:28:48 +03:00
|
|
|
|
/*
|
|
|
|
|
Procedures
|
|
|
|
|
*/
|
2017-04-03 22:29:17 +03:00
|
|
|
|
|
2024-05-13 22:28:48 +03:00
|
|
|
|
// Chapel procedures have similar syntax functions in other languages.
|
2017-04-03 22:29:17 +03:00
|
|
|
|
proc fibonacci(n : int) : int {
|
|
|
|
|
if n <= 1 then return n;
|
|
|
|
|
return fibonacci(n-1) + fibonacci(n-2);
|
2015-07-13 02:17:23 +03:00
|
|
|
|
}
|
|
|
|
|
|
2017-04-03 22:29:17 +03:00
|
|
|
|
// Input parameters can be untyped to create a generic procedure.
|
|
|
|
|
proc doublePrint(thing): void {
|
|
|
|
|
write(thing, " ", thing, "\n");
|
2015-07-13 02:17:23 +03:00
|
|
|
|
}
|
|
|
|
|
|
2017-04-03 22:29:17 +03:00
|
|
|
|
// The return type can be inferred, as long as the compiler can figure it out.
|
|
|
|
|
proc addThree(n) {
|
2015-07-13 02:17:23 +03:00
|
|
|
|
return n + 3;
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-03 22:29:17 +03:00
|
|
|
|
doublePrint(addThree(fibonacci(20)));
|
2015-07-13 02:17:23 +03:00
|
|
|
|
|
2017-04-03 22:29:17 +03:00
|
|
|
|
// It is also possible to take a variable number of parameters.
|
|
|
|
|
proc maxOf(x ...?k) {
|
2015-07-13 02:17:23 +03:00
|
|
|
|
// x refers to a tuple of one type, with k elements
|
|
|
|
|
var maximum = x[1];
|
2017-04-03 22:29:17 +03:00
|
|
|
|
for i in 2..k do maximum = if maximum < x[i] then x[i] else maximum;
|
2015-07-13 02:17:23 +03:00
|
|
|
|
return maximum;
|
|
|
|
|
}
|
2017-04-03 22:29:17 +03:00
|
|
|
|
writeln(maxOf(1, -10, 189, -9071982, 5, 17, 20001, 42));
|
2015-07-13 02:17:23 +03:00
|
|
|
|
|
2017-04-03 22:29:17 +03:00
|
|
|
|
// 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);
|
|
|
|
|
}
|
2015-07-13 02:17:23 +03:00
|
|
|
|
|
2017-04-03 22:29:17 +03:00
|
|
|
|
writeln(defaultsProc(10));
|
|
|
|
|
writeln(defaultsProc(x=11));
|
|
|
|
|
writeln(defaultsProc(x=12, y=5.432));
|
|
|
|
|
writeln(defaultsProc(y=9.876, x=13));
|
|
|
|
|
|
2024-05-13 22:28:48 +03:00
|
|
|
|
// The ``?`` operator is called the query operator, and is used to take
|
2017-04-03 22:29:17 +03:00
|
|
|
|
// undetermined values like tuple or array sizes and generic types.
|
|
|
|
|
// For example, taking arrays as parameters. The query operator is used to
|
2024-05-13 22:28:48 +03:00
|
|
|
|
// determine the domain of ``A``. This is useful for defining the return type,
|
2017-04-03 22:29:17 +03:00
|
|
|
|
// though it's not required.
|
|
|
|
|
proc invertArray(A: [?D] int): [D] int{
|
2015-07-13 02:17:23 +03:00
|
|
|
|
for a in A do a = -a;
|
|
|
|
|
return A;
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-03 22:29:17 +03:00
|
|
|
|
writeln(invertArray(intArray));
|
2015-07-13 02:17:23 +03:00
|
|
|
|
|
2017-04-03 22:29:17 +03:00
|
|
|
|
// 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);
|
|
|
|
|
|
2024-05-13 22:28:48 +03:00
|
|
|
|
// We can also enforce a form of polymorphism with the ``where`` clause
|
2017-04-03 22:29:17 +03:00
|
|
|
|
// 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");
|
2015-07-13 02:17:23 +03:00
|
|
|
|
}
|
|
|
|
|
|
2017-04-03 22:29:17 +03:00
|
|
|
|
proc whereProc(param N : int): void
|
|
|
|
|
where (N < 0) {
|
|
|
|
|
writeln("N is less than 0");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
whereProc(10);
|
|
|
|
|
whereProc(-1);
|
|
|
|
|
|
2024-05-13 22:28:48 +03:00
|
|
|
|
// ``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
|
2017-04-03 22:29:17 +03:00
|
|
|
|
// that would then have served as a catch all for all the other cases
|
|
|
|
|
// (of which there is only one).
|
|
|
|
|
|
2024-05-13 22:28:48 +03:00
|
|
|
|
// ``where`` clauses can also be used to constrain based on argument type.
|
2017-04-03 22:29:17 +03:00
|
|
|
|
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");
|
|
|
|
|
|
2024-05-13 22:28:48 +03:00
|
|
|
|
/*
|
|
|
|
|
Intents
|
|
|
|
|
*/
|
2017-04-03 22:29:17 +03:00
|
|
|
|
|
|
|
|
|
/* 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));
|
2015-07-15 04:40:53 +03:00
|
|
|
|
inarg = inarg + 100;
|
|
|
|
|
outarg = outarg + 100;
|
|
|
|
|
inoutarg = inoutarg + 100;
|
|
|
|
|
refarg = refarg + 100;
|
2017-04-03 22:29:17 +03:00
|
|
|
|
writeln("Inside After: ", (inarg, outarg, inoutarg, refarg));
|
2015-07-15 04:40:53 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var inVar: int = 1;
|
|
|
|
|
var outVar: int = 2;
|
|
|
|
|
var inoutVar: int = 3;
|
|
|
|
|
var refVar: int = 4;
|
2017-04-03 22:29:17 +03:00
|
|
|
|
writeln("Outside Before: ", (inVar, outVar, inoutVar, refVar));
|
|
|
|
|
intentsProc(inVar, outVar, inoutVar, refVar);
|
|
|
|
|
writeln("Outside After: ", (inVar, outVar, inoutVar, refVar));
|
2015-07-15 22:08:15 +03:00
|
|
|
|
|
2017-04-03 22:29:17 +03:00
|
|
|
|
// Similarly, we can define intents on the return type.
|
2024-05-13 22:28:48 +03:00
|
|
|
|
// ``refElement`` returns a reference to an element of array.
|
2015-10-02 19:31:25 +03:00
|
|
|
|
// This makes more practical sense for class methods where references to
|
2017-04-03 22:29:17 +03:00
|
|
|
|
// elements in a data-structure are returned via a method or iterator.
|
|
|
|
|
proc refElement(array : [?D] ?T, idx) ref : T {
|
|
|
|
|
return array[idx];
|
2015-07-13 02:17:23 +03:00
|
|
|
|
}
|
|
|
|
|
|
2017-04-03 22:29:17 +03:00
|
|
|
|
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);
|
2015-07-13 02:17:23 +03:00
|
|
|
|
|
2024-05-13 22:28:48 +03:00
|
|
|
|
/*
|
|
|
|
|
Operator Definitions
|
|
|
|
|
*/
|
2015-07-13 02:17:23 +03:00
|
|
|
|
|
2017-04-03 22:29:17 +03:00
|
|
|
|
// Chapel allows for operators to be overloaded.
|
2015-07-15 05:07:59 +03:00
|
|
|
|
// We can define the unary operators:
|
2024-05-13 22:28:48 +03:00
|
|
|
|
// ``+ - ! ~``
|
2015-07-13 02:17:23 +03:00
|
|
|
|
// and the binary operators:
|
2024-05-13 22:28:48 +03:00
|
|
|
|
// ``+ - * / % ** == <= >= < > << >> & | ˆ by``
|
|
|
|
|
// ``+= -= *= /= %= **= &= |= ˆ= <<= >>= <=>``
|
2015-07-13 02:17:23 +03:00
|
|
|
|
|
2017-04-03 22:29:17 +03:00
|
|
|
|
// Boolean exclusive or operator.
|
|
|
|
|
proc ^(left : bool, right : bool): bool {
|
|
|
|
|
return (left || right) && !(left && right);
|
2015-07-13 02:17:23 +03:00
|
|
|
|
}
|
|
|
|
|
|
2017-04-03 22:29:17 +03:00
|
|
|
|
writeln(true ^ true);
|
|
|
|
|
writeln(false ^ true);
|
|
|
|
|
writeln(true ^ false);
|
|
|
|
|
writeln(false ^ false);
|
2015-07-13 02:17:23 +03:00
|
|
|
|
|
2024-05-13 22:28:48 +03:00
|
|
|
|
// Define a ``*`` operator on any two types that returns a tuple of those types.
|
2017-04-03 22:29:17 +03:00
|
|
|
|
proc *(left : ?ltype, right : ?rtype): (ltype, rtype) {
|
|
|
|
|
writeln("\tIn our '*' overload!");
|
|
|
|
|
return (left, right);
|
2015-07-13 02:17:23 +03:00
|
|
|
|
}
|
|
|
|
|
|
2024-05-13 22:28:48 +03:00
|
|
|
|
writeln(1 * "a"); // Uses our ``*`` operator.
|
|
|
|
|
writeln(1 * 2); // Uses the default ``*`` operator.
|
2017-04-03 22:29:17 +03:00
|
|
|
|
|
|
|
|
|
// Note: You could break everything if you get careless with your overloads.
|
|
|
|
|
// This here will break everything. Don't do it.
|
2015-07-13 02:17:23 +03:00
|
|
|
|
|
2024-05-13 22:28:48 +03:00
|
|
|
|
/*
|
|
|
|
|
|
|
|
|
|
proc +(left: int, right: int): int {
|
|
|
|
|
return left - right;
|
|
|
|
|
}
|
2015-07-13 02:17:23 +03:00
|
|
|
|
*/
|
|
|
|
|
|
2024-05-13 22:28:48 +03:00
|
|
|
|
/*
|
|
|
|
|
Iterators
|
|
|
|
|
*/
|
2017-04-03 22:29:17 +03:00
|
|
|
|
|
|
|
|
|
// 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 {
|
2015-07-15 05:07:59 +03:00
|
|
|
|
for i in 1..N by 2 do
|
2015-07-15 04:40:53 +03:00
|
|
|
|
yield i; // yield values instead of returning.
|
2015-07-15 05:07:59 +03:00
|
|
|
|
for i in 2..N by 2 do
|
2015-07-15 04:40:53 +03:00
|
|
|
|
yield i;
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-03 22:29:17 +03:00
|
|
|
|
for i in oddsThenEvens(10) do write(i, ", ");
|
|
|
|
|
writeln();
|
2015-07-15 04:40:53 +03:00
|
|
|
|
|
2015-08-06 04:22:56 +03:00
|
|
|
|
// Iterators can also yield conditionally, the result of which can be nothing
|
2017-04-03 22:29:17 +03:00
|
|
|
|
iter absolutelyNothing(N): int {
|
2015-08-06 04:22:56 +03:00
|
|
|
|
for i in 1..N {
|
2017-04-03 22:29:17 +03:00
|
|
|
|
if N < i { // Always false
|
2015-08-06 04:22:56 +03:00
|
|
|
|
yield i; // Yield statement never happens
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-03 22:29:17 +03:00
|
|
|
|
for i in absolutelyNothing(10) {
|
|
|
|
|
writeln("Woa there! absolutelyNothing yielded ", i);
|
2015-08-06 04:22:56 +03:00
|
|
|
|
}
|
|
|
|
|
|
2015-10-02 19:31:25 +03:00
|
|
|
|
// We can zipper together two or more iterators (who have the same number
|
2024-05-13 22:28:48 +03:00
|
|
|
|
// of iterations) using ``zip()`` to create a single zipped iterator, where each
|
2015-10-02 19:31:25 +03:00
|
|
|
|
// iteration of the zipped iterator yields a tuple of one value yielded
|
2015-08-03 00:35:41 +03:00
|
|
|
|
// from each iterator.
|
2017-04-03 22:29:17 +03:00
|
|
|
|
for (positive, negative) in zip(1..5, -5..-1) do
|
|
|
|
|
writeln((positive, negative));
|
2015-08-02 03:02:51 +03:00
|
|
|
|
|
2015-10-02 19:31:25 +03:00
|
|
|
|
// Zipper iteration is quite important in the assignment of arrays,
|
2015-08-06 04:22:56 +03:00
|
|
|
|
// slices of arrays, and array/loop expressions.
|
|
|
|
|
var fromThatArray : [1..#5] int = [1,2,3,4,5];
|
|
|
|
|
var toThisArray : [100..#5] int;
|
|
|
|
|
|
2017-04-03 22:29:17 +03:00
|
|
|
|
// Some zipper operations implement other operations.
|
|
|
|
|
// The first statement and the loop are equivalent.
|
2015-08-06 04:22:56 +03:00
|
|
|
|
toThisArray = fromThatArray;
|
2017-04-03 22:29:17 +03:00
|
|
|
|
for (i,j) in zip(toThisArray.domain, fromThatArray.domain) {
|
|
|
|
|
toThisArray[i] = fromThatArray[j];
|
2015-08-06 04:22:56 +03:00
|
|
|
|
}
|
|
|
|
|
|
2017-04-03 22:29:17 +03:00
|
|
|
|
// These two chunks are also equivalent.
|
|
|
|
|
toThisArray = [j in -100..#5] j;
|
|
|
|
|
writeln(toThisArray);
|
|
|
|
|
|
|
|
|
|
for (i, j) in zip(toThisArray.domain, -100..#5) {
|
2015-08-06 04:22:56 +03:00
|
|
|
|
toThisArray[i] = j;
|
|
|
|
|
}
|
2017-04-03 22:29:17 +03:00
|
|
|
|
writeln(toThisArray);
|
|
|
|
|
|
2024-05-13 22:28:48 +03:00
|
|
|
|
// This is very important in understanding why this statement exhibits a runtime error.
|
2017-04-03 22:29:17 +03:00
|
|
|
|
|
2024-05-13 22:28:48 +03:00
|
|
|
|
/*
|
|
|
|
|
var iterArray : [1..10] int = [i in 1..10] if (i % 2 == 1) then i;
|
2017-04-03 22:29:17 +03:00
|
|
|
|
*/
|
2015-08-06 04:22:56 +03:00
|
|
|
|
|
2015-10-02 19:31:25 +03:00
|
|
|
|
// Even though the domain of the array and the loop-expression are
|
2015-10-08 14:14:24 +03:00
|
|
|
|
// the same size, the body of the expression can be thought of as an iterator.
|
2015-08-06 04:22:56 +03:00
|
|
|
|
// 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.
|
|
|
|
|
|
2024-05-13 22:28:48 +03:00
|
|
|
|
/*
|
|
|
|
|
Classes
|
|
|
|
|
*/
|
2017-04-03 22:29:17 +03:00
|
|
|
|
// Classes are similar to those in C++ and Java, allocated on the heap.
|
2015-07-13 02:17:23 +03:00
|
|
|
|
class MyClass {
|
2017-04-03 22:29:17 +03:00
|
|
|
|
|
|
|
|
|
// Member variables
|
2015-10-02 19:31:25 +03:00
|
|
|
|
var memberInt : int;
|
|
|
|
|
var memberBool : bool = true;
|
2015-07-13 02:17:23 +03:00
|
|
|
|
|
2024-05-13 22:28:48 +03:00
|
|
|
|
// By default, any class that doesn't define an initializer gets a
|
|
|
|
|
// compiler-generated initializer, with one argument per field and
|
|
|
|
|
// the field's initial value as the argument's default value.
|
|
|
|
|
// Alternatively, the user can define initializers manually as shown
|
|
|
|
|
// in the following commented-out routine:
|
|
|
|
|
//
|
|
|
|
|
/* // proc init(val : real) {
|
|
|
|
|
// this.memberInt = ceil(val): int;
|
|
|
|
|
// }
|
|
|
|
|
*/
|
2015-07-13 02:17:23 +03:00
|
|
|
|
|
2017-04-03 22:29:17 +03:00
|
|
|
|
// 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));
|
2015-07-13 02:17:23 +03:00
|
|
|
|
}
|
|
|
|
|
|
2017-04-03 22:29:17 +03:00
|
|
|
|
// Class methods.
|
|
|
|
|
proc setMemberInt(val: int) {
|
2015-07-13 02:17:23 +03:00
|
|
|
|
this.memberInt = val;
|
|
|
|
|
}
|
2015-10-02 19:31:25 +03:00
|
|
|
|
|
2017-04-03 22:29:17 +03:00
|
|
|
|
proc setMemberBool(val: bool) {
|
2015-07-13 02:17:23 +03:00
|
|
|
|
this.memberBool = val;
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-03 22:29:17 +03:00
|
|
|
|
proc getMemberInt(): int{
|
2015-07-13 02:17:23 +03:00
|
|
|
|
return this.memberInt;
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-03 22:29:17 +03:00
|
|
|
|
proc getMemberBool(): bool {
|
2015-07-13 02:17:23 +03:00
|
|
|
|
return this.memberBool;
|
|
|
|
|
}
|
2017-04-03 22:29:17 +03:00
|
|
|
|
} // end MyClass
|
|
|
|
|
|
|
|
|
|
// Call compiler-generated initializer, using default value for memberBool.
|
2024-05-13 22:28:48 +03:00
|
|
|
|
{
|
|
|
|
|
var myObject = new owned MyClass(10);
|
|
|
|
|
myObject = new owned MyClass(memberInt = 10); // Equivalent
|
|
|
|
|
writeln(myObject.getMemberInt());
|
|
|
|
|
|
|
|
|
|
// Same, but provide a memberBool value explicitly.
|
|
|
|
|
var myDiffObject = new owned MyClass(-1, true);
|
|
|
|
|
myDiffObject = new owned MyClass(memberInt = -1,
|
|
|
|
|
memberBool = true); // Equivalent
|
|
|
|
|
writeln(myDiffObject);
|
|
|
|
|
|
|
|
|
|
// Similar, but rely on the default value of memberInt, passing in memberBool.
|
|
|
|
|
var myThirdObject = new owned MyClass(memberBool = true);
|
|
|
|
|
writeln(myThirdObject);
|
|
|
|
|
|
|
|
|
|
// If the user-defined initializer above had been uncommented, we could
|
|
|
|
|
// make the following calls:
|
|
|
|
|
//
|
|
|
|
|
/* // 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());
|
|
|
|
|
}
|
2015-07-13 02:17:23 +03:00
|
|
|
|
|
2024-05-13 22:28:48 +03:00
|
|
|
|
var plusObject = myObject + myDiffObject;
|
|
|
|
|
writeln(plusObject);
|
2015-07-13 02:17:23 +03:00
|
|
|
|
|
2024-05-13 22:28:48 +03:00
|
|
|
|
// 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.
|
|
|
|
|
}
|
2015-07-13 02:17:23 +03:00
|
|
|
|
|
|
|
|
|
// Classes can inherit from one or more parent classes
|
|
|
|
|
class MyChildClass : MyClass {
|
|
|
|
|
var memberComplex: complex;
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-03 22:29:17 +03:00
|
|
|
|
// Here's an example of generic classes.
|
2015-07-13 02:17:23 +03:00
|
|
|
|
class GenericClass {
|
|
|
|
|
type classType;
|
|
|
|
|
var classDomain: domain(1);
|
|
|
|
|
var classArray: [classDomain] classType;
|
2015-10-02 19:31:25 +03:00
|
|
|
|
|
2024-05-13 22:28:48 +03:00
|
|
|
|
// Explicit initializer.
|
|
|
|
|
proc init(type classType, elements : int) {
|
|
|
|
|
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.
|
2015-07-13 02:17:23 +03:00
|
|
|
|
}
|
2015-10-02 19:31:25 +03:00
|
|
|
|
|
2024-05-13 22:28:48 +03:00
|
|
|
|
// Copy-style initializer.
|
|
|
|
|
// Note: We include a type argument whose default is the type of the first
|
|
|
|
|
// argument. This lets our initializer copy classes of different
|
|
|
|
|
// types and cast on the fly.
|
|
|
|
|
proc init(other : GenericClass(?),
|
|
|
|
|
type classType = other.classType) {
|
|
|
|
|
this.classType = classType;
|
2015-07-13 02:17:23 +03:00
|
|
|
|
this.classDomain = other.classDomain;
|
2024-05-13 22:28:48 +03:00
|
|
|
|
this.classArray = for o in other do o: classType; // copy and cast
|
2015-07-13 02:17:23 +03:00
|
|
|
|
}
|
2015-10-02 19:31:25 +03:00
|
|
|
|
|
2017-04-03 22:29:17 +03:00
|
|
|
|
// Define bracket notation on a GenericClass
|
|
|
|
|
// object so it can behave like a normal array
|
2024-05-13 22:28:48 +03:00
|
|
|
|
// i.e. ``objVar[i]`` or ``objVar(i)``
|
2017-04-03 22:29:17 +03:00
|
|
|
|
proc this(i : int) ref : classType {
|
|
|
|
|
return this.classArray[i];
|
2015-07-13 02:17:23 +03:00
|
|
|
|
}
|
2015-10-02 19:31:25 +03:00
|
|
|
|
|
2017-04-03 22:29:17 +03:00
|
|
|
|
// Define an implicit iterator for the class
|
|
|
|
|
// to yield values from the array to a loop
|
2024-05-13 22:28:48 +03:00
|
|
|
|
// i.e. ``for i in objVar do ...``
|
2017-04-03 22:29:17 +03:00
|
|
|
|
iter these() ref : classType {
|
2015-07-13 02:17:23 +03:00
|
|
|
|
for i in this.classDomain do
|
|
|
|
|
yield this[i];
|
|
|
|
|
}
|
2017-04-03 22:29:17 +03:00
|
|
|
|
} // end GenericClass
|
2015-10-02 19:31:25 +03:00
|
|
|
|
|
2024-05-13 22:28:48 +03:00
|
|
|
|
// Allocate an owned instance of our class
|
|
|
|
|
var realList = new owned GenericClass(real, 10);
|
|
|
|
|
|
2015-10-02 19:31:25 +03:00
|
|
|
|
// We can assign to the member array of the object using the bracket
|
2017-04-03 22:29:17 +03:00
|
|
|
|
// notation that we defined.
|
2015-07-13 02:17:23 +03:00
|
|
|
|
for i in realList.classDomain do realList[i] = i + 1.0;
|
2017-04-03 22:29:17 +03:00
|
|
|
|
|
2015-10-02 19:31:25 +03:00
|
|
|
|
// We can iterate over the values in our list with the iterator
|
2017-04-03 22:29:17 +03:00
|
|
|
|
// we defined.
|
|
|
|
|
for value in realList do write(value, ", ");
|
|
|
|
|
writeln();
|
2015-07-13 02:17:23 +03:00
|
|
|
|
|
2024-05-13 22:28:48 +03:00
|
|
|
|
// Make a copy of realList using the copy initializer.
|
|
|
|
|
var copyList = new owned GenericClass(realList);
|
2017-04-03 22:29:17 +03:00
|
|
|
|
for value in copyList do write(value, ", ");
|
|
|
|
|
writeln();
|
2015-07-13 02:17:23 +03:00
|
|
|
|
|
2024-05-13 22:28:48 +03:00
|
|
|
|
// Make a copy of realList and change the type, also using the copy initializer.
|
|
|
|
|
var copyNewTypeList = new owned GenericClass(realList, int);
|
2017-04-03 22:29:17 +03:00
|
|
|
|
for value in copyNewTypeList do write(value, ", ");
|
|
|
|
|
writeln();
|
|
|
|
|
|
|
|
|
|
|
2024-05-13 22:28:48 +03:00
|
|
|
|
/*
|
|
|
|
|
Modules
|
|
|
|
|
*/
|
2015-07-13 02:17:23 +03:00
|
|
|
|
|
2015-08-03 01:37:01 +03:00
|
|
|
|
// Modules are Chapel's way of managing name spaces.
|
|
|
|
|
// The files containing these modules do not need to be named after the modules
|
2015-08-03 02:05:19 +03:00
|
|
|
|
// (as in Java), but files implicitly name modules.
|
2024-05-13 22:28:48 +03:00
|
|
|
|
// For example, this file implicitly names the ``learnChapelInYMinutes`` module
|
2015-07-13 02:17:23 +03:00
|
|
|
|
|
2015-08-03 01:37:01 +03:00
|
|
|
|
module OurModule {
|
2015-10-02 19:31:25 +03:00
|
|
|
|
|
2017-04-03 22:29:17 +03:00
|
|
|
|
// 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) {
|
2015-08-03 01:37:01 +03:00
|
|
|
|
for i in 1..seconds by -1 {
|
2017-04-03 22:29:17 +03:00
|
|
|
|
writeln(i);
|
|
|
|
|
sleep(1);
|
2015-08-03 01:37:01 +03:00
|
|
|
|
}
|
2015-10-02 19:31:25 +03:00
|
|
|
|
}
|
|
|
|
|
|
2017-04-03 22:29:17 +03:00
|
|
|
|
// It is possible to create arbitrarily deep module nests.
|
|
|
|
|
// i.e. submodules of OurModule
|
2015-08-03 01:37:01 +03:00
|
|
|
|
module ChildModule {
|
2017-04-03 22:29:17 +03:00
|
|
|
|
proc foo() {
|
|
|
|
|
writeln("ChildModule.foo()");
|
2015-08-03 01:37:01 +03:00
|
|
|
|
}
|
2015-07-13 02:17:23 +03:00
|
|
|
|
}
|
2015-10-02 19:31:25 +03:00
|
|
|
|
|
2015-08-03 01:37:01 +03:00
|
|
|
|
module SiblingModule {
|
2017-04-03 22:29:17 +03:00
|
|
|
|
proc foo() {
|
|
|
|
|
writeln("SiblingModule.foo()");
|
2015-08-03 01:37:01 +03:00
|
|
|
|
}
|
2015-07-20 05:59:30 +03:00
|
|
|
|
}
|
2015-08-03 01:37:01 +03:00
|
|
|
|
} // end OurModule
|
|
|
|
|
|
2024-05-13 22:28:48 +03:00
|
|
|
|
// Using ``OurModule`` also uses all the modules it uses.
|
|
|
|
|
// Since ``OurModule`` uses ``Time``, we also use ``Time``.
|
2015-08-03 01:37:01 +03:00
|
|
|
|
use OurModule;
|
|
|
|
|
|
2024-05-13 22:28:48 +03:00
|
|
|
|
// 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.
|
2017-04-03 22:29:17 +03:00
|
|
|
|
SiblingModule.foo();
|
|
|
|
|
OurModule.ChildModule.foo();
|
2015-08-03 01:37:01 +03:00
|
|
|
|
|
2024-05-13 22:28:48 +03:00
|
|
|
|
// Now we use ``ChildModule``, enabling unqualified calls.
|
2015-08-03 01:37:01 +03:00
|
|
|
|
use ChildModule;
|
2017-04-03 22:29:17 +03:00
|
|
|
|
foo();
|
|
|
|
|
|
2024-05-13 22:28:48 +03:00
|
|
|
|
/*
|
|
|
|
|
Parallelism
|
|
|
|
|
*/
|
2017-04-03 22:29:17 +03:00
|
|
|
|
|
|
|
|
|
// In other languages, parallelism is typically done with
|
|
|
|
|
// complicated libraries and strange class structure hierarchies.
|
|
|
|
|
// Chapel has it baked right into the language.
|
2015-08-03 01:37:01 +03:00
|
|
|
|
|
2017-04-03 22:29:17 +03:00
|
|
|
|
// We can declare a main procedure, but all the code above main still gets
|
|
|
|
|
// executed.
|
|
|
|
|
proc main() {
|
2015-08-03 01:37:01 +03:00
|
|
|
|
|
2024-05-13 22:28:48 +03:00
|
|
|
|
// A ``begin`` statement will spin the body of that statement off
|
2017-04-03 22:29:17 +03:00
|
|
|
|
// into one new task.
|
2024-05-13 22:28:48 +03:00
|
|
|
|
// A ``sync`` statement will ensure that the progress of the main
|
2017-04-03 22:29:17 +03:00
|
|
|
|
// task will not progress until the children have synced back up.
|
2015-08-03 01:37:01 +03:00
|
|
|
|
|
|
|
|
|
sync {
|
|
|
|
|
begin { // Start of new task's body
|
|
|
|
|
var a = 0;
|
|
|
|
|
for i in 1..1000 do a += 1;
|
2017-04-03 22:29:17 +03:00
|
|
|
|
writeln("Done: ", a);
|
2015-08-03 01:37:01 +03:00
|
|
|
|
} // End of new tasks body
|
2017-04-03 22:29:17 +03:00
|
|
|
|
writeln("spun off a task!");
|
2015-08-03 01:37:01 +03:00
|
|
|
|
}
|
2017-04-03 22:29:17 +03:00
|
|
|
|
writeln("Back together");
|
2015-07-20 05:59:30 +03:00
|
|
|
|
|
2017-04-03 22:29:17 +03:00
|
|
|
|
proc printFibb(n: int) {
|
|
|
|
|
writeln("fibonacci(",n,") = ", fibonacci(n));
|
2015-08-03 01:37:01 +03:00
|
|
|
|
}
|
2015-07-20 18:09:28 +03:00
|
|
|
|
|
2024-05-13 22:28:48 +03:00
|
|
|
|
// A ``cobegin`` statement will spin each statement of the body into one new
|
2017-04-03 22:29:17 +03:00
|
|
|
|
// task. Notice here that the prints from each statement may happen in any
|
|
|
|
|
// order.
|
2015-08-03 01:37:01 +03:00
|
|
|
|
cobegin {
|
2017-04-03 22:29:17 +03:00
|
|
|
|
printFibb(20); // new task
|
|
|
|
|
printFibb(10); // new task
|
|
|
|
|
printFibb(5); // new task
|
2015-10-02 19:31:25 +03:00
|
|
|
|
{
|
2015-08-03 01:37:01 +03:00
|
|
|
|
// This is a nested statement body and thus is a single statement
|
2017-04-03 22:29:17 +03:00
|
|
|
|
// to the parent statement, executed by a single task.
|
|
|
|
|
writeln("this gets");
|
|
|
|
|
writeln("executed as");
|
|
|
|
|
writeln("a whole");
|
2015-08-03 01:37:01 +03:00
|
|
|
|
}
|
2015-07-20 18:09:28 +03:00
|
|
|
|
}
|
|
|
|
|
|
2024-05-13 22:28:48 +03:00
|
|
|
|
// A ``coforall`` loop will create a new task for EACH iteration.
|
2017-04-03 22:29:17 +03:00
|
|
|
|
// Again we see that prints happen in any order.
|
2024-05-13 22:28:48 +03:00
|
|
|
|
// NOTE: ``coforall`` should be used only for creating tasks!
|
2017-04-03 22:29:17 +03:00
|
|
|
|
// Using it to iterating over a structure is very a bad idea!
|
2015-08-03 01:37:01 +03:00
|
|
|
|
var num_tasks = 10; // Number of tasks we want
|
2024-05-13 22:28:48 +03:00
|
|
|
|
coforall taskID in 1..num_tasks {
|
2017-04-03 22:29:17 +03:00
|
|
|
|
writeln("Hello from task# ", taskID);
|
2015-08-03 01:37:01 +03:00
|
|
|
|
}
|
|
|
|
|
|
2024-05-13 22:28:48 +03:00
|
|
|
|
// ``forall`` loops are another parallel loop, but only create a smaller number
|
|
|
|
|
// of tasks, specifically ``--dataParTasksPerLocale=`` number of tasks.
|
2015-08-03 01:37:01 +03:00
|
|
|
|
forall i in 1..100 {
|
2017-04-03 22:29:17 +03:00
|
|
|
|
write(i, ", ");
|
2015-08-03 01:37:01 +03:00
|
|
|
|
}
|
2017-04-03 22:29:17 +03:00
|
|
|
|
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
|
|
|
|
|
|
2024-05-13 22:28:48 +03:00
|
|
|
|
// For both the ``forall`` and ``coforall`` loops, the execution of the
|
2017-04-03 22:29:17 +03:00
|
|
|
|
// parent task will not continue until all the children sync up.
|
|
|
|
|
|
2024-05-13 22:28:48 +03:00
|
|
|
|
// ``forall`` loops are particularly useful for parallel iteration over arrays.
|
2017-04-03 22:29:17 +03:00
|
|
|
|
// Lets run an experiment to see how much faster a parallel loop is
|
2015-08-03 01:37:01 +03:00
|
|
|
|
use Time; // Import the Time module to use Timer objects
|
2015-10-02 19:31:25 +03:00
|
|
|
|
var timer: Timer;
|
2015-08-03 01:37:01 +03:00
|
|
|
|
var myBigArray: [{1..4000,1..4000}] real; // Large array we will write into
|
|
|
|
|
|
2017-04-03 22:29:17 +03:00
|
|
|
|
// Serial Experiment:
|
|
|
|
|
timer.start(); // Start timer
|
2015-08-03 01:37:01 +03:00
|
|
|
|
for (x,y) in myBigArray.domain { // Serial iteration
|
|
|
|
|
myBigArray[x,y] = (x:real) / (y:real);
|
|
|
|
|
}
|
2017-04-03 22:29:17 +03:00
|
|
|
|
timer.stop(); // Stop timer
|
|
|
|
|
writeln("Serial: ", timer.elapsed()); // Print elapsed time
|
|
|
|
|
timer.clear(); // Clear timer for parallel loop
|
2015-08-03 01:37:01 +03:00
|
|
|
|
|
2017-04-03 22:29:17 +03:00
|
|
|
|
// Parallel Experiment:
|
|
|
|
|
timer.start(); // start timer
|
2015-08-03 01:37:01 +03:00
|
|
|
|
forall (x,y) in myBigArray.domain { // Parallel iteration
|
|
|
|
|
myBigArray[x,y] = (x:real) / (y:real);
|
|
|
|
|
}
|
2017-04-03 22:29:17 +03:00
|
|
|
|
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
|
2024-05-13 22:28:48 +03:00
|
|
|
|
// much earlier implicitly uses a ``forall`` loop.
|
2017-04-03 22:29:17 +03:00
|
|
|
|
[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.
|
2024-05-13 22:28:48 +03:00
|
|
|
|
// Chapel atomic variables can be of type ``bool``, ``int``,
|
|
|
|
|
// ``uint``, and ``real``.
|
2015-08-03 01:37:01 +03:00
|
|
|
|
var uranium: atomic int;
|
2017-04-03 22:29:17 +03:00
|
|
|
|
uranium.write(238); // atomically write a variable
|
|
|
|
|
writeln(uranium.read()); // atomically read a variable
|
2015-08-03 01:37:01 +03:00
|
|
|
|
|
2017-04-03 22:29:17 +03:00
|
|
|
|
// Atomic operations are described as functions, so you can define your own.
|
|
|
|
|
uranium.sub(3); // atomically subtract a variable
|
|
|
|
|
writeln(uranium.read());
|
2015-08-03 01:37:01 +03:00
|
|
|
|
|
|
|
|
|
var replaceWith = 239;
|
2017-04-03 22:29:17 +03:00
|
|
|
|
var was = uranium.exchange(replaceWith);
|
|
|
|
|
writeln("uranium was ", was, " but is now ", replaceWith);
|
2015-08-03 01:37:01 +03:00
|
|
|
|
|
|
|
|
|
var isEqualTo = 235;
|
2024-05-13 22:28:48 +03:00
|
|
|
|
if uranium.compareAndSwap(isEqualTo, replaceWith) {
|
2017-04-03 22:29:17 +03:00
|
|
|
|
writeln("uranium was equal to ", isEqualTo,
|
|
|
|
|
" so replaced value with ", replaceWith);
|
2015-08-03 01:37:01 +03:00
|
|
|
|
} else {
|
2017-04-03 22:29:17 +03:00
|
|
|
|
writeln("uranium was not equal to ", isEqualTo,
|
|
|
|
|
" so value stays the same... whatever it was");
|
2015-07-20 05:59:30 +03:00
|
|
|
|
}
|
|
|
|
|
|
2015-08-03 01:37:01 +03:00
|
|
|
|
sync {
|
|
|
|
|
begin { // Reader task
|
2017-04-03 22:29:17 +03:00
|
|
|
|
writeln("Reader: waiting for uranium to be ", isEqualTo);
|
|
|
|
|
uranium.waitFor(isEqualTo);
|
|
|
|
|
writeln("Reader: uranium was set (by someone) to ", isEqualTo);
|
2015-08-03 01:37:01 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
begin { // Writer task
|
2017-04-03 22:29:17 +03:00
|
|
|
|
writeln("Writer: will set uranium to the value ", isEqualTo, " in...");
|
|
|
|
|
countdown(3);
|
|
|
|
|
uranium.write(isEqualTo);
|
2015-08-03 01:37:01 +03:00
|
|
|
|
}
|
2015-07-20 05:59:30 +03:00
|
|
|
|
}
|
|
|
|
|
|
2024-05-13 22:28:48 +03:00
|
|
|
|
// ``sync`` variables have two states: empty and full.
|
2017-04-03 22:29:17 +03:00
|
|
|
|
// If you read an empty variable or write a full variable, you are waited
|
|
|
|
|
// until the variable is full or empty again.
|
2015-08-03 01:37:01 +03:00
|
|
|
|
var someSyncVar$: sync int; // varName$ is a convention not a law.
|
|
|
|
|
sync {
|
|
|
|
|
begin { // Reader task
|
2017-04-03 22:29:17 +03:00
|
|
|
|
writeln("Reader: waiting to read.");
|
2015-08-03 01:37:01 +03:00
|
|
|
|
var read_sync = someSyncVar$;
|
2017-04-03 22:29:17 +03:00
|
|
|
|
writeln("Reader: value is ", read_sync);
|
2015-08-03 01:37:01 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
begin { // Writer task
|
2017-04-03 22:29:17 +03:00
|
|
|
|
writeln("Writer: will write in...");
|
|
|
|
|
countdown(3);
|
2015-10-05 07:02:33 +03:00
|
|
|
|
someSyncVar$ = 123;
|
2015-07-20 05:59:30 +03:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-13 22:28:48 +03:00
|
|
|
|
// ``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.
|
2015-08-03 01:37:01 +03:00
|
|
|
|
var someSingleVar$: single int; // varName$ is a convention not a law.
|
|
|
|
|
sync {
|
|
|
|
|
begin { // Reader task
|
2017-04-03 22:29:17 +03:00
|
|
|
|
writeln("Reader: waiting to read.");
|
2015-08-03 01:37:01 +03:00
|
|
|
|
for i in 1..5 {
|
|
|
|
|
var read_single = someSingleVar$;
|
2017-04-03 22:29:17 +03:00
|
|
|
|
writeln("Reader: iteration ", i,", and the value is ", read_single);
|
2015-08-03 01:37:01 +03:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
begin { // Writer task
|
2017-04-03 22:29:17 +03:00
|
|
|
|
writeln("Writer: will write in...");
|
|
|
|
|
countdown(3);
|
2015-08-03 01:37:01 +03:00
|
|
|
|
someSingleVar$ = 5; // first and only write ever.
|
|
|
|
|
}
|
2015-07-20 05:59:30 +03:00
|
|
|
|
}
|
2015-07-23 05:08:22 +03:00
|
|
|
|
|
2024-05-13 22:28:48 +03:00
|
|
|
|
// Here's an example using atomics and a ``sync`` variable to create a
|
2017-04-03 22:29:17 +03:00
|
|
|
|
// count-down mutex (also known as a multiplexer).
|
2015-08-03 01:37:01 +03:00
|
|
|
|
var count: atomic int; // our counter
|
|
|
|
|
var lock$: sync bool; // the mutex lock
|
|
|
|
|
|
2017-04-03 22:29:17 +03:00
|
|
|
|
count.write(2); // Only let two tasks in at a time.
|
|
|
|
|
lock$.writeXF(true); // Set lock$ to full (unlocked)
|
2017-08-23 11:14:39 +03:00
|
|
|
|
// Note: The value doesn't actually matter, just the state
|
2015-08-03 01:37:01 +03:00
|
|
|
|
// (full:unlocked / empty:locked)
|
|
|
|
|
// Also, writeXF() fills (F) the sync var regardless of its state (X)
|
|
|
|
|
|
2024-05-13 22:28:48 +03:00
|
|
|
|
coforall task in 1..5 { // Generate tasks
|
2015-08-03 01:37:01 +03:00
|
|
|
|
// Create a barrier
|
2017-04-03 22:29:17 +03:00
|
|
|
|
do {
|
2015-08-03 01:37:01 +03:00
|
|
|
|
lock$; // Read lock$ (wait)
|
2017-04-03 22:29:17 +03:00
|
|
|
|
} while (count.read() < 1); // Keep waiting until a spot opens up
|
2015-10-02 19:31:25 +03:00
|
|
|
|
|
2015-08-03 01:37:01 +03:00
|
|
|
|
count.sub(1); // decrement the counter
|
2017-04-03 22:29:17 +03:00
|
|
|
|
lock$.writeXF(true); // Set lock$ to full (signal)
|
2015-10-02 19:31:25 +03:00
|
|
|
|
|
2015-08-03 01:37:01 +03:00
|
|
|
|
// Actual 'work'
|
2017-04-03 22:29:17 +03:00
|
|
|
|
writeln("Task #", task, " doing work.");
|
|
|
|
|
sleep(2);
|
2015-08-02 03:02:51 +03:00
|
|
|
|
|
2017-04-03 22:29:17 +03:00
|
|
|
|
count.add(1); // Increment the counter
|
|
|
|
|
lock$.writeXF(true); // Set lock$ to full (signal)
|
2015-08-03 01:37:01 +03:00
|
|
|
|
}
|
2015-08-02 03:02:51 +03:00
|
|
|
|
|
2024-05-13 22:28:48 +03:00
|
|
|
|
// We can define the operations ``+ * & | ^ && || min max minloc maxloc``
|
2017-04-03 22:29:17 +03:00
|
|
|
|
// over an entire array using scans and reductions.
|
|
|
|
|
// Reductions apply the operation over the entire array and
|
|
|
|
|
// result in a scalar value.
|
2015-08-03 01:37:01 +03:00
|
|
|
|
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
|
|
|
|
|
|
2024-05-13 22:28:48 +03:00
|
|
|
|
// ``maxloc`` gives max value and index of the max value.
|
2017-04-03 22:29:17 +03:00
|
|
|
|
// Note: We have to zip the array and domain together with the zip iterator.
|
2015-10-02 19:31:25 +03:00
|
|
|
|
var (theMaxValue, idxOfMax) = maxloc reduce zip(listOfValues,
|
2015-08-03 01:37:01 +03:00
|
|
|
|
listOfValues.domain);
|
2015-10-02 19:31:25 +03:00
|
|
|
|
|
2017-04-03 22:29:17 +03:00
|
|
|
|
writeln((sumOfValues, maxValue, idxOfMax, listOfValues[idxOfMax]));
|
2015-08-03 01:37:01 +03:00
|
|
|
|
|
2017-04-03 22:29:17 +03:00
|
|
|
|
// Scans apply the operation incrementally and return an array with the
|
|
|
|
|
// values of the operation at that index as it progressed through the
|
2024-05-13 22:28:48 +03:00
|
|
|
|
// array from ``array.domain.low`` to ``array.domain.high``.
|
2015-08-03 01:37:01 +03:00
|
|
|
|
var runningSumOfValues = + scan listOfValues;
|
|
|
|
|
var maxScan = max scan listOfValues;
|
2017-04-03 22:29:17 +03:00
|
|
|
|
writeln(runningSumOfValues);
|
|
|
|
|
writeln(maxScan);
|
2015-08-03 02:05:19 +03:00
|
|
|
|
} // end main()
|
2015-07-13 02:40:32 +03:00
|
|
|
|
```
|
2015-07-18 03:21:14 +03:00
|
|
|
|
|
2024-04-26 12:13:48 +03:00
|
|
|
|
## Who is this tutorial for?
|
2015-07-18 03:21:14 +03:00
|
|
|
|
|
2017-04-03 22:29:17 +03:00
|
|
|
|
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.
|
2017-11-02 22:22:33 +03:00
|
|
|
|
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
|
2017-04-03 22:29:17 +03:00
|
|
|
|
details.
|
2015-07-15 03:44:55 +03:00
|
|
|
|
|
2017-11-02 22:22:33 +03:00
|
|
|
|
Occasionally check back here and on the [Chapel site](https://chapel-lang.org)
|
2017-04-03 22:29:17 +03:00
|
|
|
|
to see if more topics have been added or more tutorials created.
|
2015-07-15 03:44:55 +03:00
|
|
|
|
|
2015-07-15 05:07:59 +03:00
|
|
|
|
### What this tutorial is lacking:
|
2015-07-18 03:21:14 +03:00
|
|
|
|
|
2024-04-26 12:13:48 +03:00
|
|
|
|
* Exposition of the [standard modules](https://chapel-lang.org/docs/latest/modules/standard.html)
|
|
|
|
|
* Multiple Locales (distributed memory system)
|
|
|
|
|
* Records
|
|
|
|
|
* Parallel iterators
|
2015-07-15 05:07:59 +03:00
|
|
|
|
|
2024-04-26 12:13:48 +03:00
|
|
|
|
## Your input, questions, and discoveries are important to the developers!
|
2015-07-18 03:21:14 +03:00
|
|
|
|
|
2018-07-23 19:20:21 +03:00
|
|
|
|
The Chapel language is still in active development, so there are
|
2017-04-03 22:29:17 +03:00
|
|
|
|
occasional hiccups with performance and language features. The more information
|
|
|
|
|
you give the Chapel development team about issues you encounter or features you
|
2018-07-23 19:20:21 +03:00
|
|
|
|
would like to see, the better the language becomes.
|
|
|
|
|
There are several ways to interact with the developers:
|
2024-04-26 12:13:48 +03:00
|
|
|
|
|
|
|
|
|
* [Gitter chat](https://gitter.im/chapel-lang/chapel)
|
|
|
|
|
* [sourceforge email lists](https://sourceforge.net/p/chapel/mailman)
|
2015-07-15 03:44:55 +03:00
|
|
|
|
|
2017-04-03 22:29:17 +03:00
|
|
|
|
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).
|
2015-07-15 03:44:55 +03:00
|
|
|
|
It is under the [Apache 2.0 License](http://www.apache.org/licenses/LICENSE-2.0).
|
|
|
|
|
|
2024-04-26 12:13:48 +03:00
|
|
|
|
## Installing the Compiler
|
2015-07-18 03:21:14 +03:00
|
|
|
|
|
2018-07-24 04:04:27 +03:00
|
|
|
|
[The Official Chapel documentation details how to download and compile the Chapel compiler.](https://chapel-lang.org/docs/usingchapel/QUICKSTART.html)
|
|
|
|
|
|
2015-07-15 03:44:55 +03:00
|
|
|
|
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/)
|
2015-10-05 07:02:33 +03:00
|
|
|
|
and it's as easy as
|
2015-07-18 03:21:14 +03:00
|
|
|
|
|
2024-04-26 12:13:48 +03:00
|
|
|
|
1. `tar -xvf chapel-<VERSION>.tar.gz`
|
|
|
|
|
2. `cd chapel-<VERSION>`
|
|
|
|
|
3. `source util/setchplenv.bash # or .sh or .csh or .fish`
|
|
|
|
|
4. `make`
|
|
|
|
|
5. `make check # optional`
|
2015-07-15 03:44:55 +03:00
|
|
|
|
|
2017-04-03 22:29:17 +03:00
|
|
|
|
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).
|
2015-07-15 03:44:55 +03:00
|
|
|
|
|
2024-04-26 12:13:48 +03:00
|
|
|
|
Chapel is easily installed on macOS with Homebrew
|
2015-07-18 03:21:14 +03:00
|
|
|
|
|
2024-04-26 12:13:48 +03:00
|
|
|
|
1. `brew update`
|
|
|
|
|
2. `brew install chapel`
|
2015-07-15 03:44:55 +03:00
|
|
|
|
|
2024-04-26 12:13:48 +03:00
|
|
|
|
## Compiling Code
|
2015-07-17 20:15:29 +03:00
|
|
|
|
|
2015-07-18 03:21:14 +03:00
|
|
|
|
Builds like other compilers:
|
|
|
|
|
|
2015-08-03 01:44:16 +03:00
|
|
|
|
`chpl myFile.chpl -o myExe`
|
2015-07-15 03:44:55 +03:00
|
|
|
|
|
2015-07-20 23:07:23 +03:00
|
|
|
|
Notable arguments:
|
2015-07-15 03:44:55 +03:00
|
|
|
|
|
2024-04-26 12:13:48 +03:00
|
|
|
|
* `--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.
|