Chapter 2. Programming Methodology

Table of Contents

2.1. Syntactic and Stylistic Conventions
2.1.1. Parallel combinator
2.1.2. Sequential combinator
2.1.3. Pruning combinator
2.1.4. Declarations
2.2. Programming Idioms
2.2.1. Channels
2.2.2. Lists
2.2.3. Streams
2.2.4. Arrays
2.2.5. Mutable Storage
2.2.6. Loops
2.2.7. Parallel Matching
2.2.8. Fork-join
2.2.9. Sequential Fork-Join
2.2.10. Priority Poll
2.2.11. Parallel Or
2.2.12. Timeout
2.2.13. Priority
2.2.14. Metronome
2.2.15. Routing
2.2.16. Interruption
2.2.17. Lifting
2.2.18. Fold
2.3. Larger Examples
2.3.1. Dining Philosophers
2.3.2. Hygienic Dining Philosophers
2.3.3. Readers-Writers
2.3.4. Quicksort
2.3.5. Meeting Scheduler

In Chapter 1, we described the syntax and semantics of the Orc language. Now, we turn our attention to how the language is used in practice, with guidelines on style and programming methodology, including a number of common concurrency patterns.

2.1. Syntactic and Stylistic Conventions

In this section we suggest some syntactic conventions for writing Orc programs. None of these conventions are required by the parser; newlines are used only to disambiguate certain corner cases in parsing, and other whitespace is ignored. However, following programming convention helps to improve the readability of programs, so that the programmer's intent is more readily apparent.

2.1.1. Parallel combinator

When the combined expressions are small, write them all on one line.

F | G | H
Note that we do not need parentheses here, since | is fully associative and commutative.

When the combined expressions are large enough to take up a full line, write one expression per line, with each subsequent expression aligned with the first and preceded by |. Indent the first expression to improve readability.

  long expression 
| long expression
| long expression

A sequence of parallel expressions often form the left hand side of a sequential combinator. Since the sequential combinator has higher precedence, use parentheses to group the combined parallel expressions together.

( expression 
| expression
) >x> 
another expression

2.1.2. Sequential combinator

When the combined expressions are small, write a cascade of sequential combinators all on the same line.

F >x> G >y> H

Remember that sequential is right associative; in this example, x is bound in both G and H, and y is bound in H.

When the combined expressions are large enough to take up a full line, write one expression per line; each line ends with the combinator which binds the publications produced by that line.

long expression  >x>  
long expression  >y> 
long expression

For very long-running expressions, or expressions that span multiple lines, write the combinators on separate lines, indented, between each expression.

very long expression 
  >x>  
very long expression 
  >y> 
very long expression

2.1.3. Pruning combinator

When the combined expressions are small, write them on the same line:

F <x< G
When multiple pruning combinators are used to bind multiple variables (especially when the scoped expression is long), start each line with a combinator, aligned and indented, and continue with the expression.
long expression 
  <x< G
  <y< H

The pruning combinator is not often written in its explicit form in Orc programs. Instead, the val declaration is often more convenient, since it is semantically equivalent and mentions the variable x before its use in scope, rather than after.

val x = G
val y = H
long expression 

Additionally, when the variable is used in only one place, and the expression is small, it is often easier to use a nested expression. For example,

val x = G
val y = H
M(x,y)
is equivalent to
M(G,H)

Sometimes, we use the pruning combinator simply for its capability to terminate expressions and get a single publication; binding a variable is irrelevant. This is a special case of nested expressions. We use the identity site let to put the expression in the context of a function call.

For example,

x <x< F | G | H
is equivalent to
let(F | G | H)

The translation uses a pruning combinator, but we don't need to write the combinator, name an irrelevant variable, or worry about precedence (since the expression is enclosed in parentheses as part of the call).

2.1.4. Declarations

Declarations should always end with a newline.

def add(x,y) = x + y
val z = 7
add(z,z)
While the parser does not require a newline to end a declaration, it uses the newline to disambiguate certain corner cases in parsing, such as function application.

When the body of a declaration spans multiple lines, start the body on a new line after the = symbol, and indent the entire body.

def f(x,y) =
    declaration
    declaration
    body expression

Apply this style recursively; if a def appears within a def, indent its contents even further.

def f(x,y) =
    declaration
    def helper(z) =
    	declaration in helper
    	declaration in helper
    	body of helper
    declaration
    body expression