Getting Started

As a Python user, you are accustomed to running and having Python readily available on almost every machine you use. Chapel is equivalently portable (and more so). However, since Chapel is an emerging technology, it is not quite part of the standard software stack that comes bundled with your operating system. You therefore need to go ahead and download and install Chapel on your system.

If you are using a popular Linux-based operating system you will most likely be successful by running these commands:

# Download and unpack
cd /tmp
curl -L -O http://sourceforge.net/projects/chapel/files/chapel/1.9.0/chapel-1.9.0.tar.gz
tar xzf chapel-1.9.0.tar.gz
mv /tmp/chapel-1.9.0 ~/chapel

# Build Chapel
cd ~/chapel
make

# Setup your environment, add this command to ~/.bashrc for permanent installation.
source ~/chapel/util/setchplenv.bash

After doing the above you should be able to:

# Compile an example program
chpl -o hello ~/examples/hello.chpl
# Run it
./hello

Running “./hello” should output:

Hello, world!

If you are running MacOSX, Windows, or for some other the reason the above commands does not work for you then consult the official quick start instructions.

Compiling

What is that!? A binary! Ohh my…

Chapel is currently a compiled language. However, it lets you write and compile very simple programs. There is no annoying boiler-plate needed to get going.

Python   Chapel
print "Hello, World!"
 
writeln("Hello, World!");

And if you like to structure your code, Chapel has neat means for doing so.

Python   Chapel
def main():
    print "Hello, World!"

if __name__ == "__main__":
    main()
 
module Hello {
    proc main() {
    	writeln("Hello, World!");
    }
}

All examples in this tutorial / reference guide are compilable. Which means that you can take any snippet and put it into a file like exploring.chpl and compile it:

chpl -o exploring exploring.chpl

Which will create a binary named exploring to execute whatever you have written in exploring.chpl.

Language Basics

This section provides an informal language reference. It takes you through the base language features of Python and provides an example of how an equivalent program would be expressed in Chapel.

Variables and Types

In Python, variables are implicitly declared and their type determined when they are assigned to. In Chapel, variable declaration is explicit, but the type of the variable can be inferred from its use in a manner equivalent to that of Python.

Python   Chapel
answer = 42
distance = 123.45
computer = "Earth"

 
var answer = 42;
var distance = 123.45;
var computer = "Earth";

Types in Python are dynamic, meaning that a variable can change type during its lifetime. The type of a variable in Chapel is static and inferred at compile-time, which means that a type is assigned and cannot be changed at runtime.

Comments

Python   Chapel
# Single-line comment

"""
    Multi-line comments
"""
 
// Single-line comment

/*
    Multi-line comment
*/

Literals

These work in much the same way that you are used to. A brief overview is provided below.

Python   Chapel
bl = True        # Booleans
bl = False

ud = 42          # Unsigned digits
sd = -42         # Signed digits

hd = 0x2A        # Hex-Digits
hd = 0X2A

bd = 0b101010    # Binary-Digits
bd = 0B101010

r = 42.0        # Reals

s = '42'        # Strings

s = "42"

# Complex / imaginary
z = 1 + 2.0j

# Complex accessors
z.real    # For the real part
z.imag    # For for imaginary part
 
var bl = true;       // Booleans
    bl = false;

var ud = 42;         // Unsigned digits
var sd = -42;        // Signed digits

var hd = 0x2A;       // Hex-Digits
    hd = 0X2A;

var bd = 0b101010;   // Binary-Digits
    bd = 0B101010;

var r = 42.0;       // Reals

var s = '42';       // Strings
    s = "42";

// Complex / imaginary
var z = 1 + 2.0i;           // Common
    z = (1.0, 2.0):complex; // Alternative syntax

// Complex accessors
z.re;       // For the real part
z.im;       // For the imaginary part

Console input / output

You can write to the console (standard output) using write and writeln:

Python   Chapel
print "Hello, you."     # With a newline
print "Hello, you.",    # Without a newline
 
writeln("Hello, you."); // With a newline
write("Hello, you.");   // Without a newline

You can read input from the console (standard input) using read and readln:

Python   Chapel
first_answer = raw_input(
    "The Answer to the ultimate question is?\n"
)
print "That is", int(first_answer) == 42

second_answer = raw_input(
    "What is the largest biological computer?\n"
)
print "That is", str(second_answer) == "Earth"
 
writeln("The Answer to the Ultimate Question is?");
var first_answer = read(int);

writeln("That is ", first_answer == 42);

writeln("What is the largest biological computer?");
var second_answer = read(string);

writeln("That is ", second_answer == "Earth");

Note

Notice that the interface for reading input is quite different, though equally simple. In Python you need to explicitly cast the input, whereas in Chapel the type of the input is provided to the read/readln functions directly.

Conditionals and Blocks

Python is famous for using an indentation guided block-structure, thereby arguably improving readability and increasing consistency of code-style. Chapel uses curly-brackets to denote the start and end of a block.

Python   Chapel
#
light = raw_input("Which color is the traffic light?\n")

if light == "green":
    print "You can cross the street now."


if light == "green":
    print "You can cross the street now."
else:
    print "Wait for the green light."


if light == "green":
    print "You can cross the street now."
elif light == "yellow":
    print "CAUTION!"


if light == "green":
    print "You can cross the street now."
elif light == "yellow":
    print "CAUTION!"
else:
    print "Do not cross!"
 
writeln("Which color is the traffic light?");
var light = read(string);

if light == "green" {
    writeln("You can cross the street now.");
}

if light == "green" {
    writeln("You can cross the street now.");
} else {
    writeln("Wait for the green light.");
}

if light == "green" {
    writeln("You can cross the street now.");
} else if light == "yellow" {
    writeln("CAUTION!");
}

if light == "green" {
    writeln("You can cross the street now.");
} else if light == "yellow" {
    writeln("CAUTION!");
} else {
    writeln("Do not cross!");
}

Switch / Case

Python does not support switch-statements and instead relies on chaining if-elif-else statements.

Chapel, on the other hand, does have switch-statements, specifically select-when-otherwise statements:

Python   Chapel
#
light = raw_input("Which color is the traffic light?\n")

if light=="green":
    print "You can cross the street now."
elif light=="yellow":
    print "CAUTION!"
elif light=="red":
    print "Do not cross!"
else:
    print "WARNING! Traffic-light is broken!"






 
writeln("Which color is the traffic light?");
var light = read(string);

select(light) {
    when "green" {
        writeln("You can cross the street now.");
    }
    when "yellow" {
        writeln("CAUTION!");
    }
    when "red" {
        writeln("Do not cross!");
    }
    otherwise {
        writeln("WARNING! Traffic-light is broken!");
    }
}

Note

Notice that in both Python and Chapel these forms of switch-statements do not fall through, meaning that one and only one case will be executed. Coming from Python, this might not surpise you; however, if you have ever written a switch-statement in other languages then this may be slightly surprising.

Ranges

In Python range is a list-constructor often used for driving for-loops or list comprehensions. For lowered memory consumption, Python provides the generator equivalent of range namely xrange.

In Chapel a range is a language construct which behaves and is used in much the same way as lists are used in Python. Where you would think about lists and slicing operations in Python, think of ranges in Chapel.

Python   Chapel
r1 = xrange(1, 10) # yields 1, 2, 3, 4, 5, 6, 7, 8, 9
r2 = xrange(10, 1) # yields nothing
 
var ns = 1..9;  // yields 1, 2, 3, 4, 5, 6, 7, 8, 9
    ns = 9..1;  // yields nothing

Note

Difference in bounds!

  • In Python, range return values in the interval [start, stop[.
  • In Chapel a range-expression yields values the interval [start, stop].

For both languages the above is a shorthand of the wider form: start, stop, step.

Python   Chapel
# Values in ascending order
r1 = xrange(1, 10, 1) # yields 1, 2, 3, 4, 5, 6, 7, 8, 9
r2 = xrange(1, 10, 2) # yields 1, 3, 5, 7, 9

# Values in descending order
r3 = xrange(9, 0, -1) # yields 9, 8, 7, 6, 5, 4, 3, 2, 1
r4 = xrange(9, 0, -2) # yields 9, 7, 5, 3, 1
 
// Values in ascending order
var ns = 1..9 by 1; // yields 1, 2, 3, 4, 5, 6, 7, 8, 9
    ns = 1..9 by 2; // yields 1, 3, 5, 7, 9

// Values in descending order
    ns = 1..9 by -1; // yields 9, 8, 7, 6, 5, 4, 3, 2, 1
    ns = 1..9 by -2; // yields 9, 7, 5, 3, 1

Python   Chapel
# No equivalent in Python
 
// Infinite ranges
var one_to_inf = 1..; // yields from one to infinity: 1, 2, 3, 4, 5, ...
var inf_to_one = ..1; // yields from infinity to one: ..., -5, -4, -3 , -2, -1, 0, 1
var inf_to_inf = .. ; // yields from infinity to infinity: ... , ...

Python   Chapel
# yields 10 values: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
ns = xrange(10)
 
// yields 10 values: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
var ns = 0.. # 10; 

Loops

Python   Chapel
# Using generators
for i in xrange(1, 10):
    print i
 
// Using ranges
for i in 1..10 {
    writeln(i);
}
Python   Chapel
for i, v in enumerate(['running', 'with', 'scissors']):
    print i, v
 
for (i, v) in zip(1.. , ["running", "with", "scissors"]) {
    writeln(i, ' ', v);        
}
Python   Chapel
i = 0
while i<10: # while loop
    i += 1
    print i


i = 0       # do-while look-a-like loop
cond = True
while cond:
    i += 1
    print i
    cond = i<10
 
var i = 0;  // while loop
while i<10 {
    i += 1;
    writeln(i);
}

i = 0;      // do-while loop
do {
    i += 1;
    writeln(i);
} while(i<10);

Functions and Types

Python   Chapel
def abs(x):
    if x < 0:
        return -x
    else:
        return x
 
proc abs(x) {
    if (x < 0) then
        return -x;
    else
        return x;
}

Variable arguments? Argument unpacking? Return values? Return type declaration?

Lists, Arrays, Tuples, and Dicts

In Python, lists are an essential built-in datastructure. You might be frightened to learn that lists are not particularly useful in Chapel. However, fear not. Many of the uses of lists in Python are handled by ranges, such as driving loops. So if that is your primary concern, then take another look at the description of ranges above.

If you need the ability to have elements of different types in a container such as:

stuff = ['a string', 42, ['another', 'list', 'with', 'strings']]

Then take a look at tuples in the following section.

If you use lists for processing various forms of data of the same type, then what you need are Chapel arrays. Yes, that is correct, Chapel actually has arrays as first-class citizens in the language. Chapel is, to a great extent, all about arrays.

Tuples

Tuples work in ways quite familiar to a Python programmer. Tuples are among other things useful for packing and unpacking return-values from functions and having sequences of varying types.

Python   Chapel
coord = ('47.606165', '-122.332233');   # Assignment
print "coord =", coord
                                    ## Tuple item access
                                    #  - Indexing
print "Latitude =", coord[0], \
    ", Longitude =", coord[1]

(latitude, longitude) = coord;      #  - Unpacking

print "Latitude =", latitude, \
    ", Longitude =", longitude
 
var coord = (47.606165, -122.332233);   // Assignment
writeln("coord = ", coord);
                                    /// Tuple item access
                                    //  - Indexing
writeln(
    "Latitude = ", coord(1),
  ", Longitude = ", coord(2)
);

var (latitude, longitude) = coord;  //  - Unpacking

writeln(
    "Latitude = ", latitude,
  ", Longitude = ", longitude
);

Note

Indexing scheme of tuples.

  • In Python, tuple-indexing is 0-based.
  • In Chapel, tuple-indexing is 1-based.

Note

Mutability of tuples.

  • In Python, tuples are immutable.
  • In Chapel, tuples are mutable.

Arrays

This section only scratches the surface of Arrays in Chapel. The use of arrays and concepts related to them are described in greater detail in the section on data parallelism.

Since Python does not support arrays within the language, a comparison to the widespread and popular array-library NumPy is used as a reference instead. The first example below illustrates the creation and iteration over a 10x10 array containing 64-bit floating point numbers.

Python   Chapel
import numpy as np

A = np.zeros((10, 10), dtype=np.float64)

for a in np.nditer(A):  # Element iteration
    print a


for i in xrange(0, 10): # Index iteration
    for j in xrange(0, 10):
        print "(%d,%d) = %f" % (i, j, A[i,j])
 
// No need to import, arrays are built-in

var A: [0..9, 0..9] real;

for a in A {            // Element iteration
    writeln(a);
}
                        // Index iteration
for (i, j) in A.domain {
    writeln("(",i,",",j,") = ",A[i,j]);
}

Note

Domains an unfamiliar concept!

The array syntax and semantics should be easy to follow. The interesting thing to notice is the use of .domain when doing indexed iteration. A domain is a powerful concept and you will be very pleased with it once you get to know it. However, it does require an introduction.

A domain defines a set of indexes. When iterating over the domain associated with an array, as in the example above, you effectively iterate over all the indexes of all elements in the array. You might be accustomed to 0-based indexing from Python when using lists and tuples. With Chapel you can define whether you want your arrays to be 0-based or 1-based. In the example above, the array is 0-based since the indexes are defined by the range 0..9. If you would prefer 1-based arrays you would define it using the range 1..10 instead.

This is quite a powerful feature. When using arrays as abstractions for matrices, you might find it useful to use 1-based indexing and in other situations a different indexing scheme. With Chapel you can define the index-set and scheme that is most convenient for the domain you are working within.

Initialization

Python   Chapel
import numpy as np

A = np.arange(1, 11, dtype=np.float64)

print A
 
// No need to import, arrays are built-in

var A: [1..10] real = 1..10;

writeln(A);

Whole-array operations.

Python   Chapel
import numpy as np


B = np.random.random((10,10))
C = np.random.random((10,10))

A = B + 2.0 * C

for a in np.nditer(A):
    print a
 
use Random;

config const mySeed = SeedGenerator.currentTime;  // Allow caller to set seed

var A, B, C: [1..10, 1..10] real;
fillRandom(B, mySeed);      // Fill with random values
fillRandom(C, mySeed);

A = B + 2.0 * C;    // Whole-array operations

for a in A {        // Print the result
    writeln(a);
}

Reductions and scans

Python   Chapel
import numpy as np

A = np.arange(1, 11, dtype=np.float64)

print np.sum( A )       # Reduction

print np.cumsum( A )    # Scan
 
// No need to import, arrays are built-in

var A: [1..10] real = 1..10;

writeln( +reduce(A) );  // Reduction

writeln( +scan(A) );    // Scan

Function promotion

Python   Chapel
import numpy as np

def unary(element):
    return element*3

def binary(e1, e2):
    return (e1+e2)*3



A = np.arange(1, 11, dtype=np.float64)
B = np.arange(1, 11, dtype=np.float64)

print np.sqrt( A )      # Rely on NumPy ufuncs
print map(unary, A)     # Or mapping functions
print map(binary, A, B) # Or mapping functions
 
// No need to import, arrays are built-in

proc unary(element) {       // User-defined functions
    return element*3;
}

proc binary(e1, e2) {
    return (e1+e2)*3;
}

var A, B: [1..10] real = 1..10;


writeln( sqrt(A) );         // Promotion of built-in
writeln( unary(A) );        // Promotion of userdef unary
writeln( binary(A, B) );    // Promotion of userdef binary

Dictionaries (Associative Arrays)

Dict-comprehension?

Classes and Objects

In Python, everything is an object and all objects have a textual representation defined by the object.str(), etc. is there equivalent functionality in Chapel?

Python   Chapel
class Stoplight:

    def __init__(self, color):
        self.color = color




sl = Stoplight("Green")

print sl.color
 
class Stoplight {
    var color: string;

    proc Stoplight(color: string) {
        this.color = color;
    }
}

var sl = new Stoplight("Green");

writeln(sl.color);

Organizing Code

Python names modules implicitly via the filename convention. Chapel allows you to use the filename, but also allows you to define it explicitly through the “module” directive. You can also define and use submodules, or modules defined within the scope of another module.

Python   Chapel
def main():
    pass

if __name__ == "__main__":
    main()
 
module Hello {
    proc main() {

    }
}
Python   Chapel
from random import *

# Other means of importing
import random
assert random.Random
from random import Random
 
use Random;

// There are no equivalent means of
// of importing where the namespaces
// are maintained.