Ra code can use a number of control flow constructs. These are needed less often than in traditional programming languages, since they can be replaced with relational operators in many cases.
    Code blocks in Ra are surrounded by
    begin
    and
    end
    (like
    Pascal) rather than the more C-like
    {
    and
    }. 
This is because
    {
    and
    }
    are used instead for sets, and so used to build relations, tuples and sets of attributes etc.
  
Conditionals
Standard
    if/else
    is supported, along with
    elseif
    for multiple tests.
a := 7
if a > 5 begin
    print("a is large")
end
  if tuple{SNO:="S2", PNO:="P2", QTY:=400} ∈ SP begin
    print("exists")
end else begin
    print("does not exist")
end
  if a > 10 begin
    print("a is very large")
end elseif a > 5 begin
    print("a is large")
end else begin
    print("a is small")
end
  Loops
The
    while
    loop handles explicit iteration but, before using it, consider how a join could be used instead.
i := 0
while i < 7 begin
    print("iteration", i)
    i := i + 1
end
  The
    while
    loop can be broken out of using
    break
    or you can skip to the next iteration (if there is to be one) using
    continue.
i := 0
while i < 7 begin
    if i = 2 begin
        continue
    end
    print("iteration", i)
    if i > 4 begin
        break
    end
    i := i + 1
end
  loop
  There is a built-in
    loop
    relation generator which can sometimes remove the need for a while loop. 
It has a number of optional parameters:
    from,
    to,
    size
    and effectively generates
    iota.
You can pass one or more of these to generate a loop relation of the desired size.
For example, passing a size:
loop & dee(size:=3)
  | size | from | to | iota | 
|---|---|---|---|
| 3 | 0 | 2 | 0 | 
| 3 | 0 | 2 | 1 | 
| 3 | 0 | 2 | 2 | 
For example, passing a size and a from (using compose this time, which removes our parameters from the results):
loop(dee(size:=5, from:=2))
  | to | iota | 
|---|---|
| 6 | 2 | 
| 6 | 3 | 
| 6 | 4 | 
| 6 | 5 | 
| 6 | 6 | 
Or passing a to (using a shorthand compose this time):
loop(to:=3)
  | from | size | iota | 
|---|---|---|
| 0 | 4 | 0 | 
| 0 | 4 | 1 | 
| 0 | 4 | 2 | 
| 0 | 4 | 3 | 
Or passing a from and a to:
loop(from:=1, to:=5)
  | size | iota | 
|---|---|
| 5 | 1 | 
| 5 | 2 | 
| 5 | 3 | 
| 5 | 4 | 
| 5 | 5 | 
    Notice how the
    iota
    is the interesting result, so we can take.
  
loop(size:=3){iota}
  | iota | 
|---|
| 0 | 
| 1 | 
| 2 | 
And from there rename iota and join it with other generators or operators.
Here's an example of a nested loop:
loop(size:=5){i:=iota} * loop(size:=3){j:=iota}
  | i | j | 
|---|---|
| 0 | 0 | 
| 0 | 1 | 
| 0 | 2 | 
| 1 | 0 | 
| 1 | 1 | 
| 1 | 2 | 
| 2 | 0 | 
| 2 | 1 | 
| 2 | 2 | 
| 3 | 0 | 
| 3 | 1 | 
| 3 | 2 | 
| 4 | 0 | 
| 4 | 1 | 
| 4 | 2 | 
Yield
Inside a relation generator,
    yield
    will issue a tuple comprising the curent values of the parameters.
The control will then continue through the rest of the generator code, meaning:
    
- You may need to wrap the yield in a condition to avoid other logic also yielding
 - If needed, you can yield more than once per set of arguments
 
given
    to check which parameters, if any, were passed in.
Ideally, a relation generator should handle all combinations of parameters being passed.
If none are passed, it's usually flagged as an error. 
If all are passed, the generator should yield if they satisfy the relation's predicate and not yield otherwise (effectively the responses for true and false).
  relgen := {x:int, y:int} begin
    if given(x, y) begin
        if y = x * 2 begin
            yield   // => true
        // else no yield => false
        end
    end elseif given(x) begin
        y := x * 2
        yield
    end elseif given(y) begin
        x := y * 0.5
        yield
    end
end
  Return
Inside a relation operator,
    return
    will return an expression as the result.
It must match the output type.
As with relation generators, you can use
    given
    to check which parameters, if any, were passed in, though all of them will typically be passed.
userop := op(r:{*}, s:{*}) {attrs(heading(r) & heading(s))} begin
    return r & s
end