/
onflow.org
Flow Playground

Operators


Operators are special symbols that perform a computation for one or more values. They are either unary, binary, or ternary.

  • Unary operators perform an operation for a single value. The unary operator symbol appears before the value.
  • Binary operators operate on two values. The binary operator symbol appears between the two values (infix).
  • Ternary operators operate on three values. The first operator symbol appears between the first and second value, the second operator symbol appears between the second and third value (infix).

Negation

The - unary operator negates an integer:

let a = 1
-a  // is `-1`

The ! unary operator logically negates a boolean:

let a = true
!a  // is `false`

Assignment

The binary assignment operator = can be used to assign a new value to a variable. It is only allowed in a statement and is not allowed in expressions.

var a = 1
a = 2
// `a` is `2`


var b = 3
var c = 4

// Invalid: The assignment operation cannot be used in an expression.
a = b = c

// Instead, the intended assignment must be written in multiple statements.
b = c
a = b

Assignments to constants are invalid.

let a = 1
// Invalid: Assignments are only for variables, not constants.
a = 2

The left-hand side of the assignment operand must be an identifier. For arrays and dictionaries, this identifier can be followed by one or more index or access expressions.

// Declare an array of integers.
let numbers = [1, 2]

// Change the first element of the array.
//
numbers[0] = 3

// `numbers` is `[3, 2]`
// Declare an array of arrays of integers.
let arrays = [[1, 2], [3, 4]]

// Change the first element in the second array
//
arrays[1][0] = 5

// `arrays` is `[[1, 2], [5, 4]]`
let dictionaries = {
  true: {1: 2},
  false: {3: 4}
}

dictionaries[false][3] = 0

// `dictionaries` is `{
//   true: {1: 2},
//   false: {3: 0}
//}`

Swapping

The binary swap operator <-> can be used to exchange the values of two variables. It is only allowed in a statement and is not allowed in expressions.

var a = 1
var b = 2
a <-> b
// `a` is `2`
// `b` is `1`

var c = 3

// Invalid: The swap operation cannot be used in an expression.
a <-> b <-> c

// Instead, the intended swap must be written in multiple statements.
b <-> c
a <-> b

Both sides of the swap operation must be variable, assignment to constants is invalid.

var a = 1
let b = 2

// Invalid: Swapping is only possible for variables, not constants.
a <-> b

Both sides of the swap operation must be an identifier, followed by one or more index or access expressions.

Arithmetic

There are four arithmetic operators:

  • Addition: +
  • Subtraction: -
  • Multiplication: *
  • Division: /
  • Remainder: %
let a = 1 + 2
// `a` is `3`

The arguments for the operators need to be of the same type. The result is always the same type as the arguments.

The division and remainder operators abort the program when the divisor is zero.

Arithmetic operations on the signed integer types Int8, Int16, Int32, Int64, Int128, Int256, and on the unsigned integer types UInt8, UInt16, UInt32, UInt64, UInt128, UInt256, do not cause values to overflow or underflow.

let a: UInt8 = 255

// Run-time error: The result `256` does not fit in the range of `UInt8`,
// thus a fatal overflow error is raised and the program aborts
//
let b = a + 1
let a: Int8 = 100
let b: Int8 = 100

// Run-time error: The result `10000` does not fit in the range of `Int8`,
// thus a fatal overflow error is raised and the program aborts
//
let c = a * b
let a: Int8 = -128

// Run-time error: The result `128` does not fit in the range of `Int8`,
// thus a fatal overflow error is raised and the program aborts
//
let b = -a

Arithmetic operations on the unsigned integer types Word8, Word16, Word32, Word64 may cause values to overflow or underflow.

For example, the maximum value of an unsigned 8-bit integer is 255 (binary 11111111). Adding 1 results in an overflow, truncation to 8 bits, and the value 0.

//    11111111 = 255
// +         1
// = 100000000 = 0
let a: Word8 = 255
a + 1 // is `0`

Similarly, for the minimum value 0, subtracting 1 wraps around and results in the maximum value 255.

//    00000000
// -         1
// =  11111111 = 255
let b: Word8 = 0
b - 1  // is `255`

Logical Operators

Logical operators work with the boolean values true and false.

  • Logical AND: a && b

    true && true  // is `true`
    
    true && false  // is `false`
    
    false && true  // is `false`
    
    false && false  // is `false`
    

    If the left-hand side is false, the right-hand side is not evaluated.

  • Logical OR: a || b

    true || true  // is `true`
    
    true || false  // is `true`
    
    false || true  // is `true`
    
    false || false // is `false`
    

    If the left-hand side is true, the right-hand side is not evaluated.

Comparison operators

Comparison operators work with boolean and integer values.

  • Equality: ==, for booleans and integers

    Both sides of the equality operator may be optional, even of different levels, so it is for example possible to compare a non-optional with a double-optional (??).

    1 == 1  // is `true`
    
    1 == 2  // is `false`
    
    true == true  // is `true`
    
    true == false  // is `false`
    
    let x: Int? = 1
    x == nil  // is `false`
    
    let x: Int = 1
    x == nil  // is `false`
    
    // Comparisons of different levels of optionals are possible.
    let x: Int? = 2
    let y: Int?? = nil
    x == y  // is `false`
    
    // Comparisons of different levels of optionals are possible.
    let x: Int? = 2
    let y: Int?? = 2
    x == y  // is `true`
    
  • Inequality: !=, for booleans and integers (possibly optional)

    Both sides of the inequality operator may be optional, even of different levels, so it is for example possible to compare a non-optional with a double-optional (??).

    1 != 1  // is `false`
    
    1 != 2  // is `true`
    
    true != true  // is `false`
    
    true != false  // is `true`
    
    let x: Int? = 1
    x != nil  // is `true`
    
    let x: Int = 1
    x != nil  // is `true`
    
    // Comparisons of different levels of optionals are possible.
    let x: Int? = 2
    let y: Int?? = nil
    x != y  // is `true`
    
    // Comparisons of different levels of optionals are possible.
    let x: Int? = 2
    let y: Int?? = 2
    x != y  // is `false`
    
  • Less than: <, for integers

    1 < 1  // is `false`
    
    1 < 2  // is `true`
    
    2 < 1  // is `false`
    
  • Less or equal than: <=, for integers

    1 <= 1  // is `true`
    
    1 <= 2  // is `true`
    
    2 <= 1  // is `false`
    
  • Greater than: >, for integers

    1 > 1  // is `false`
    
    1 > 2  // is `false`
    
    2 > 1  // is `true`
    
  • Greater or equal than: >=, for integers

    1 >= 1  // is `true`
    
    1 >= 2  // is `false`
    
    2 >= 1  // is `true`
    

Ternary Conditional Operator

There is only one ternary conditional operator, the ternary conditional operator (a ? b : c).

It behaves like an if-statement, but is an expression: If the first operator value is true, the second operator value is returned. If the first operator value is false, the third value is returned.

The first value must be a boolean (must have the type Bool). The second value and third value can be of any type. The result type is the least common supertype of the second and third value.

let x = 1 > 2 ? 3 : 4
// `x` is `4` and has type `Int`

let y = 1 > 2 ? nil : 3
// `y` is `3` and has type `Int?`

Precedence and Associativity

Operators have the following precedences, highest to lowest:

  • Unary precedence: -, !, <-
  • Cast precedence: as, as?, as!
  • Multiplication precedence: *, /, %
  • Addition precedence: +, -
  • Bitwise shift precedence: <<, >>
  • Bitwise conjunction precedence: &
  • Bitwise exclusive disjunction precedence: ^
  • Bitwise disjunction precedence: |
  • Nil-Coalescing precedence: ??
  • Relational precedence: <, <=, >, >=
  • Equality precedence: ==, !=
  • Logical conjunction precedence: &&
  • Logical disjunction precedence: ||
  • Ternary precedence: ? :

All operators are left-associative, except for the following operators which are right-associative:

  • Ternary operator
  • Nil-coalescing operator

Expressions can be wrapped in parentheses to override precedence conventions, i.e. an alternate order should be indicated, or when the default order should be emphasized e.g. to avoid confusion. For example, (2 + 3) * 4 forces addition to precede multiplication, and 5 + (6 * 7) reinforces the default order.

Edit on GitHub