Operator's Odyssey: Mastering Operators in Cadence

Operators are special symbols that perform a computation for one or more values. They are either unary (perform an operation for a single value), binary (operate on two values.), or ternary (operate on two values.)

Types of Operators

1. Assignment Operator (=)

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.

let numbers = [1, 2]

let arrays = [[1, 2], [3, 4]]

// Invalid: The assignment operation cannot be used in an expression.

a = b = c

2. Force-assignment operator (<-!)

It assigns a resource-typed value to an optional-typed variable if the variable is nil. If the variable being assigned to is non-nil, the execution of the program aborts.

The force-assignment operator is only used for resource types.

// Declare a variable named b.

var b = 1

b = 2 // valid: assigning new value.

3. Swapping Operator (<->)

It is used to exchange the values of two variables. It is only allowed in a statement and is not allowed in expressions.

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

var a = 2

var b = 1

a <-> b

b = 2 // valid: assigning new value.

let a = 2

var b = 1

a <-> b // invalid: cannot aiign to constant

3. Arithmetic Operators

3.1 The unary pefix operator - negates an integer

let a = 10

-a // is -10

3.2 Binary arithmetic operators:

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

let a = 1 + 2 //Addition

a // is 3

let b = 3 - 2 //Subtraction

b // is 1

let c = 1 * 2 //Multiplication

c // is 3

let d = 6 / 3 //Division

d // is 2

let e = 3 % 6 //Remainder

e // is 0

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

let b = a + 1 // Run-time error: The result 256 does not fit in the range of UInt8

let a: UInt8 = -128

let b = -a // Run-time error: The result 128 does not fit in the range of UInt8

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

let a: Word8 = 255

a + 1 // is 0

// 11111111 = 255

// + 1

// = 100000000 = 0

Arithmetic operators are not supported for number supertypes (Number, SignedNumber, FixedPoint, SignedFixedPoint, Integer, SignedInteger), as they may or may not succeed at run-time.

Values of these types need to be cast to the desired type before performing the arithmetic operation.

let x: Integer = 3 as Int8

let y: Integer = 4 as Int8

let z: Integer = x + y // Static error

let z: Integer = (x as! Int8) + (y as! Int8)

4. Logical Operators

4.1 Logical NOT: !

This unary prefix operator logically negates a boolean:

let good = true

!good // is false

4.1 Logical AND: &&

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

true && true // is true

true && false // is false

4.1 Logical OR: ||

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

true || true // is true

false || false // is false

5. Comparison Operators

5.1 Equality: ==

Supported for booleans, numbers, addresses, strings, characters, enums, paths, Type values, references, and Void values (()). Variable-sized arrays, fixed-size arrays, dictionaries, and optionals also support equality tests if their inner types do. 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

let x: Int? = 1

x == nil // is false

5.2 Inequality: !=

It is supported for booleans, numbers, addresses, strings, characters, enums, paths, Type values, references, and Void values (()). Variable-sized arrays, fixed-size arrays, dictionaries, and optionals also support inequality tests if their inner types do. 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 != 2 // is true

let d1 = {"abc": 1, "def": 2}

let d1 = {"abc": 1, "def": 22}

d1 != d2 // is true

5.3 Less than: <

Used for integers, booleans, characters and strings

1 < 1 // is false

"" < "a" // is true

5.4 Less or equal than: <=

Used for integers, booleans, characters and strings

true <= true // is true

2 <= 1 // is false

5.4 Greater than: >

Used for integers, booleans, characters and strings

1 > 1 // is true

"" > "a" // is false

5.4 Greater or equal than: >=

Used for integers, booleans, characters and strings

true >= true // is true

2 >= 1 // is true

6. Bitwise Operators

6.1 Bitwise AND: &

Returns a new integer whose bits are 1 only if the bits were 1 in both input integers:

let firstFiveBits = 0b11111000

let lastFiveBits = 0b00011111

let middleTwoBits = firstFiveBits & lastFiveBits // is 0b00011000

6.2 Bitwise OR: |

Returns a new integer whose bits are 1 only if the bits were 1 in either input integers:

let firstFiveBits = 0b11111000

let lastFiveBits = 0b00011111

let combinedbits = someBits | moreBits // is 0b11111110

6.2 Bitwise XOR: ^

Returns a new integer whose bits are 1 where the input bits are different, and are 0 where the input bits are the same:

let firstFiveBits = 0b11111000

let lastFiveBits = 0b00011111

let outputBits = firstBits ^ otherBits // is 0b00010001

6. 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.

let x = 1 > 2 ? 3 : 4

// x is 4 and has type Int

7. Optional Operators

7.1 Nil-Coalescing Operator (??)

The nil-coalescing operator ?? returns the value inside an optional if it contains a value, or returns an alternative value if the optional has no value, i.e., the optional value is nil.

The nil-coalescing operator can only be applied to values which have an optional type.

The type of the right-hand side of the operator (the alternative value) must be a subtype of the type of left-hand side, i.e. the right-hand side of the operator must be the non-optional or optional type matching the type of the left-hand side.

let a: Int? = nil

let b: Int = a ?? 42

// b is 42, as a is nil

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