if decides which code block to perform based on the truth of one or more conditional expressions. Consider:

fn abs(x i32) i32
  imm result i32;
  if x < 0
    result = -x
  else
    result = x
  result

if is used by this function to correctly return the positive, absolute value of x. x < 0 is a conditional expression that evaluates to true whenever x is a negative number. When the conditional evaluates as true, the subsequent block is performed, which converts x to its positive equivalent. When the conditional is not true, the block after the else is performed instead, which captures the value of x.

if variations

Before covering the logic of conditional expressions, let's summarize various ways to use if.

if as statement suffix

The else clause is optional; it need not be specified if there is no alternative action to perform when the condition is false. Furthermore, if the block consists of just one statement, then the if and condition can be written after the statement. Using this capability, we can re-implement the above function more concisely:

fn abs(x i32) i32
  return -x if x < 0
  x

if as expression

As with blocks, if can be used as an expression. This (along with implicit return) provides us with another way to write this function:

fn abs(x i32) i32
  if x < 0
    -x
  else
    x

Multiple conditions

If we have more than one condition to test, each corresponding to a different block to perform, every condition after the first is preceded with elif (short for "else if"). For example:

fn abs(x i32) i32
  if x < 0
    -x
  elif x == 0
    0
  else
    x

Conditional Expressions

Conditional expressions are often just simple comparisons, as shown above. However, complex conditional expressions can be formulated that use logical operators, pattern matching, functions or methods. Let's walk through the possibilities, beginning with the basics.

True vs. False

A conditional expression evaluates to true or false. The integer number 0, the null pointer, and false all evaluate to false. All other values evaluate to true. Thus:

// This statement will never execute
a += 1 if 0   // since 0 evaluates to false

// This statement will always execute
a += 1 if "hello"

This applies to the (first) value returned by a function or method call:

a += 1 if a.isOdd

Equivalence

With most values, we can compare whether they are the same by using an equivalence operator. The == operator returns true if two values have the same content and type. != (not equal) is true if they do not. For example:

x == 3.0        // Returns true if the local variable x's value is 3.0
x+1 != y        // Returns true if x is not exactly 1 greater than y
true != false   // Returns true

As with the arithmetic operators, the == and != operators are implemented as type-specific methods. Thus, each type can establish its own rules for equivalence. For example, two floating point numbers could be evaluated as equal if they are within some margin of error (resulting from floating point calculation rounding errors). Similarly, two lists might be equal if they have the exact same contents. A type must implement the == method to ensure its values can be compared.

Ordered Comparison

Comparison operators determine whether one value is greater or less than some other value. They work only on types that are comparable, such as numbers.

x >= 2          // Returns true if x is greater than or equal to 2 (>, <, <= are variants)
2 <= 2.0        // Returns false any time the types do not agree

Boolean Operators

Sometimes a conditional expression requires checking multiple conditions and then combining those results together into a single true/false determination. The boolean operators 'and', 'or' and 'not' ('!') are used to accomplish this. These operators are distinctly different than the bitwise logic operators ('&', '|', and '~') introduced in an earlier section.

For example:

0==3 or not 2<3 and 3==3   // Returns true ('and' is evaluated before 'or')

The logical operators work mostly how you would expect:

Expression usage

Conditional expressions need not only be found on control flow statements like if. They may also be incorporated as part of any arbitrary expression. For example:

imm isOne = (a == 1)    // isOne will be either true or false

_