Skip to main content
This page lists all the operators in FunC in decreasing order of their precedence, with examples of usage.

Table of operators

Currently, all the unary and binary operators are integer operators. Logical operators are bitwise integer operators (cf. absence of boolean type).
The following table lists operators in order of decreasing precedence, from highest to lowest.
Brief descriptionOperators
Parentheses( )
Unary bitwise NOT~
Multiplicative* / ^/ ~/ % ^% ~% /% &
Unary integer negation-
Additive+ -(integer subtraction) | ^
Shifts>> << ^>> ~>>
Comparison and Equality> >= < <= <=> == !=
Ternary?:
Assignment= and all augmented assignment operators
All binary operators are left-associative, with the exception of: Also, the ternary operator ?: is right-associative. For example:
  • 1 - 2 + 3 parses as (1 - 2) + 3, producing 2 as result.
  • a = b += c = 10 parses as (a = (b += (c = 10))), producing the final values c = 10, b = 11, and a = 11, under the assumption that b had value 1 initially.
  • 0 ? a : 1 ? b : c parses as 0 ? a : (1 ? b : c), producing b as a result.
  • 3 /% 5 /% 7 does not compile, neither (3 /% 5) /% 7 nor 3 /% (5 /% 7).
In expressions, all operators should be separated from their arguments, otherwise the expression is interpreted as an identifier.For example:
  • - x - Negates x.
  • -x - Interpreted as a single identifier, not an operation.
  • x + y - Adds x and y.
  • x+y - Interpreted as a single identifier, not an operation.

Precedence

Precedence is used to determine which operator should be considered in a particular situation. Whenever ambiguity arises, FunC prefers operators with higher precedence over those with lower precedence. For example, consider this expression:
10 - 6 * 2
The expression is ambiguous because it could be parsed in two different ways:
(10 - 6) * 2   ;; Evaluate first 10 - 6
10 - (6 * 2)   ;; Evaluate first 6 * 2
However, since the multiplication operator * has higher precedence than the subtraction operator -, FunC will prefer to evaluate the multiplication first:
10 - (6 * 2)   ;; Evaluate first 6 * 2
Neglecting precedence rules can often lead to confusing situations with operators. The correct order of operations can be ensured by wrapping every operation in parentheses, since parentheses have the highest precedence of all expressions and operators.

Parentheses

Parentheses (also called round brackets, ()) are more punctuation symbols than actual operators, but their precedence is higher than the precedence of any other operator. Use parentheses to override the order of operations:
5 * 5 - 2;    ;; 23
5 * (5 - 2);  ;; 15

Unary operators

Unary here means that they are applied only to one operand of the given expression. All unary operators are prefix operators, i.e., placed before the operand.

Bitwise NOT, ~

The tilde (bitwise NOT) operator ~ inverts or flips each bit in the binary representation of the expression, changing each 1 to 0, and vice versa.
int answer = 42;
~ answer;     ;; -43
~ (~ answer); ;; 42
~ (~ 0);      ;; 0
The ~ operator also behaves as expected on -1 and 0, which are the emulated values for true and false:
~ 0;          ;; -1,  NOT false is true 
~ (- 1);      ;; 0,   NOT true is false
Hence, ~ can work as logical NOT when computing boolean conditions:
~ (1 <= 4);    ;; 0,  since 1 <= 4 returns true (-1)
1 > 4;         ;; 0,  logically equivalent to previous

Negation, -

The minus sign (negation) operator - reverses the sign of the expression.
int five = 5;
- five;         ;; -5
- (- five);     ;; 5
- (- 1);        ;; 1

Binary operators

Binary here means that they are applied to two operands of the given expression. All binary operators are infix operators, i.e., placed in the middle of the two operands.

Multiplication, *

The asterisk (multiplication) operator * is used for multiplication of two values. Going beyond the range of the integer type will result in an error with exit code 4: Integer overflow.
int five = 5;
five * 2;         ;; 10
five * five;      ;; 25

Division, /

The slash (division) operator / is used for integer division of two values, which truncates toward zero if the result is positive and away from zero if the result is negative. This is also called rounding down or rounding toward negative infinity. An attempt to divide by zero results in an error with exit code 4: Integer overflow.
(- 1) / 5;        ;; -1, rounding down away from 0
(- 1) / (- 5);    ;; 0, rounding down toward zero
1 / (- 5);        ;; -1, rounding down away from 0
1 / 5;            ;; 0, rounding down toward 0
6 / 5;            ;; 1, rounding down toward 0
(- 6) / 5;        ;; -2, rounding down away from 0

Ceiling division, ^/

The caret-slash (ceiling division) operator ^/ is used for integer division of two values, which truncates away from zero if the result is positive and toward zero if the result is negative. This is also called rounding up or rounding toward positive infinity. An attempt to divide by zero results in an error with exit code 4: Integer overflow.
(- 1) ^/ 5;       ;; 0, rounding up toward 0
(- 1) ^/ (- 5);   ;; 1, rounding up away from zero
1 ^/ (- 5);       ;; 0, rounding up toward 0
1 ^/ 5;           ;; 1, rounding up away from 0
6 ^/ 5;           ;; 2, rounding up away from 0
(- 6) ^/ 5;       ;; -1, rounding up toward 0

Rounding division, ~/

The tilde-slash (rounding division) operator ~/ is used for integer division of two values, which truncates to the nearest integer but using the following tie-breaking rule for half values: if the fractional part is 0.5, it is truncated away from zero if the result is positive, and truncated toward zero if the result is negative. This is also called rounding half up or rounding half toward positive infinity. An attempt to divide by zero results in an error with exit code 4: Integer overflow.
(- 6) ~/ 5;      ;; -1, rounding -1.2 to nearest integer
(- 6) ~/ (- 5);  ;; 1, rounding 1.2 to nearest integer
8 ~/ (- 5);      ;; -2, rounding -1.6 to nearest integer
8 ~/ 5;          ;; 2, rounding 1.6 to nearest integer
3 ~/ 2;          ;; 2, rounding half value 1.5 away from 0
(- 3) ~/ 2;      ;; -1, rounding half value -1.5 toward 0

Modulo, %

The percent sign (modulo) operator % is used for obtaining the modulo of integer division, which is the remainder of dividing the operands with the / operator. Concretely, a % b is defined as a - (b * (a / b)), where / is the division operator, * is the multiplication operator, and - is the subtraction operator. If b in the expression a % b is 0, the result is an error with exit code 4: Integer overflow.
(- 6) % 5;       ;; 4, result of formula: -6 - (5 * (-6 / 5))
(- 6) % (- 5);   ;; -1, result of formula: -6 - (-5 * (-6 / -5))
8 % (- 5);       ;; -2, result of formula: 8 - (-5 * (8 / -5))
8 % 5;           ;; 3, result of formula: 8 - (5 * (8 / 5))
3 % 2;           ;; 1, result of formula: 3 - (2 * (3 / 2))
(- 3) % 2;       ;; 1, result of formula: -3 - (2 * (-3 / 2))
The result of % always has the same sign as the divisor (i.e., b is the divisor in the expression a % b). This means that the modulo is not the same as the remainder from Euclidean division, because in Euclidean division the remainder is always non-negative, independently of the sign of the divisor. The modulo % and the remainder from Euclidean division coincide when both operands are non-negative. If you want to compute remainders as in Euclidean division by using the % operator, the best way is to use only unsigned integers. Alternatively, consider using the abs function to ensure non-negative values:
abs(-3) % abs(-4)   ;; 3, same as 3 % 4

Ceiling modulo, ^%

The caret-percent sign (ceiling modulo) operator ^% is used for obtaining the ceiling modulo of integer ceiling division, which is the remainder of dividing the operands with the ^/ operator. Concretely, a ^% b is defined as a - (b * (a ^/ b)), where ^/ is the ceiling division operator, * is the multiplication operator, and - is the subtraction operator. If b in the expression a ^% b is 0, the result is an error with exit code 4: Integer overflow.
(- 6) ^% 5;       ;; -1, result of formula: -6 - (5 * (-6 ^/ 5))
(- 6) ^% (- 5);   ;; 4, result of formula: -6 - (-5 * (-6 ^/ -5))
8 ^% (- 5);       ;; 3, result of formula: 8 - (-5 * (8 ^/ -5))
8 ^% 5;           ;; -2, result of formula: 8 - (5 * (8 ^/ 5))
3 ^% 2;           ;; -1, result of formula: 3 - (2 * (3 ^/ 2))
(- 3) ^% 2;       ;; -1, result of formula: -3 - (2 * (-3 ^/ 2))
The result of ^% always has the opposite sign of the divisor (i.e., b is the divisor in the expression a ^% b).

Rounding modulo, ~%

The tilde-percent sign (rounding modulo) operator ~% is used for obtaining the rounding modulo of integer rounding division, which is the remainder of dividing the operands with the ~/ operator. Concretely, a ~% b is defined as a - (b * (a ~/ b)), where ~/ is the rounding division operator, * is the multiplication operator, and - is the subtraction operator. If b in the expression a ~% b is 0, the result is an error with exit code 4: Integer overflow.
(- 6) ~% 5;       ;; -1, result of formula: -6 - (5 * (-6 ~/ 5))
(- 6) ~% (- 5);   ;; -1, result of formula: -6 - (-5 * (-6 ~/ -5))
8 ~% (- 5);       ;; -2, result of formula: 8 - (-5 * (8 ~/ -5))
8 ~% 5;           ;; -2, result of formula: 8 - (5 * (8 ~/ 5))
3 ~% 2;           ;; -1, result of formula: 3 - (2 * (3 ~/ 2))
(- 3) ~% 2;       ;; -1, result of formula: -3 - (2 * (-3 ~/ 2))

Division and modulo, /%

The slash-percent sign (division and modulo) operator /% returns a two element tensor, where the first element is the result of applying the division operator / on the operands, and the second element is the result of applying the modulo operator on the operands. If b in the expression a /% b is 0, the result is an error with exit code 4: Integer overflow.
(- 6) /% 5;       ;; (-2, 4), which is: (-6 / 5, -6 % 5)
(- 6) /% (- 5);   ;; (1, -1), which is: (-6 / -5, -6 % -5)
8 /% (- 5);       ;; (-2, -2), which is: (8 / -5, 8 % -5)
8 /% 5;           ;; (1, 3), which is: (8 / 5, 8 % 5)
3 /% 2;           ;; (1, 1), which is: (3 / 2, 3 % 2)
(- 3) /% 2;       ;; (-2, 1), which is: (-3 / 2, -3 % 2)
/% is the only binary operator that does not associate to the right or to the left:
10 /% 2 /% 3;     ;; Does NOT compile 
(10 /% 2) /% 3;   ;; Does NOT compile 
10 /% (2 /% 3);   ;; Does NOT compile 
The reason for this non-associativity of /% is that it returns a 2-element tensor. This means that you must decompose the tensor before using the values. See more about decomposition notation in the variable declaration section.
(int x, int y) = 10 /% 2;    ;; x stores 5, y stores 0
(int z, int w) = x /% 3;     ;; z stores 1, w stores 2

Bitwise AND, &

The ampersand (bitwise AND) operator & applies a bitwise AND, which performs the logical AND operation on each pair of corresponding bits of the operands. This is useful when we want to clear selected bits of a number, where each bit represents an individual flag or a boolean state. This makes it possible to “store” up to 257 boolean values per integer, as all integers in FunC are 257-bit signed.
2 & 1;     ;; 0,  since 2 and 1 has no bits in common
4 & 1;     ;; 0,  since 4 and 1 has no bits in common
3 & 1;     ;; 1,  since 3 and 1 has in common only the lowest degree bit
1 & 1;     ;; 1,  & is idempotent, as expected of logical AND
The & operator also behaves as expected on -1 and 0, which are the emulated values for true and false:
0 & 0;          ;; 0,   false AND false is false 
0 & (- 1);      ;; 0,   false AND true is false
(- 1) & 0;      ;; 0,   true AND false is false
(- 1) & (- 1);  ;; -1,  true AND true is true
Hence, & can work as logical AND when computing boolean conditions:
(1 <= 4) & (2 < 3);   ;; -1,  since (1 <= 4) and (2 < 3) both return -1

Addition, +

The plus (addition) operator + is used for adding numbers together. Going beyond the range of the integer type will result in an error with exit code 4: Integer overflow.
2 + 2;      ;; 4
- 1 + 1;    ;; 0

Subtraction, -

The minus (subtraction) operator - is used for subtracting numbers from each other. Going beyond the range of the integer type will result in an error with exit code 4: Integer overflow.
2 - 2;    ;; 0
- 1 - 1;  ;; -2

Bitwise OR, |

The bar (bitwise OR) operator | applies a bitwise OR, which performs the logical OR operation on each pair of corresponding bits of the operands. This is useful when we want to apply a specific bitmask.
2 & 1;     ;; 3, 
4 & 1;     ;; 5, 
3 & 1;     ;; 3,  
1 & 1;     ;; 1,  | is idempotent, as expected of logical OR
The | operator also behaves as expected on -1 and 0, which are the emulated values for true and false:
0 | 0;          ;; 0,    false OR false is false 
0 | (- 1);      ;; -1,   false OR true is true
(- 1) | 0;      ;; -1,   true OR false is true
(- 1) | (- 1);  ;; -1,   true OR true is true
Hence, | can work as logical OR when computing boolean conditions:
(1 <= 4) | (3 < 2);   ;; -1,  since (1 <= 4) returns -1

Bitwise XOR, ^

The caret (bitwise XOR) operator ^ applies a bitwise XOR, performing the logical exclusive OR operation on each pair of corresponding bits of the operands. The result in each position is 1 if exactly one of the bits is 1, or 0 if both bits are 0 or both bits are 1. Thus, it compares two bits, yielding 1 if the bits are different and 0 if they are the same. It is useful for inverting selected bits of an operand (also called toggling or flipping), as any bit can be toggled by “XORing” it with 1.
6 ^ 2;     ;; 4, 
4 ^ 2;     ;; 6, 
3 ^ 1;     ;; 2,  
1 ^ 1;     ;; 0,
The ^ operator also behaves as expected on -1 and 0, which are the emulated values for true and false:
0 ^ 0;          ;; 0,    false XOR false is false 
0 ^ (- 1);      ;; -1,   false XOR true is true
(- 1) ^ 0;      ;; -1,   true XOR false is true
(- 1) ^ (- 1);  ;; 0,    true XOR true is false

Shift right, >>

The double greater than (shift right) operator >> returns an integer whose binary representation is the left operand value shifted by the right operand number of bits to the right. Excess bits shifted off to the right are discarded, and copies of the leftmost bit are shifted in from the left. This operation is also called “sign-propagating right shift” or “arithmetic right shift” because the sign of the resulting number is the same as the sign of the left operand. x >> n is a more efficient way to divide x by 2^n, where the division truncation is done by flooring. In other words, x >> n is equivalent to floor(x / 2^n), where floor is the floor function, 2^n is exponentiation of 2 by n, and / is standard arithmetical division.
2 >> 1;       ;; 1,  since floor(2 / 2^1) = 1
(- 2) >> 1;   ;; -1, because >> preserves the sign of the left operand,
              ;; or equivalently floor(-2 / 2^1) = -1       
 
8 >> 2;       ;; 2,  since floor(8 / 2^2) = 2
5 >> 1;       ;; 2,  since floor(5 / 2^1) = 2
(- 14) >> 2;  ;; -4  since floor(-14 / 2^2) = -4

Shift left, <<

The double less-than (shift left) operator << returns an integer whose binary representation is the left operand value shifted to the left by the number of bits specified by the right operand. Excess bits shifted off from the left are discarded, and zero bits are shifted in from the right. x << n is a more efficient way to multiply x by 2^n. In other words, x << n is equivalent to x * 2^n, where 2^n is exponentiation of 2 by n and * is standard arithmetical multiplication. Exceeding the range of the integer type will result in an error with exit code 4: Integer overflow.
2 << 1;   ;; 4,  since 2 * 2^1 = 4
1 << 5;   ;; 32, since 1 * 2^5 = 32
2 << 5;   ;; 64, since 2 * 2^5 = 64

Ceiling shift right, ^>>

The caret-double greater than (ceiling shift right) operator computes an efficient way to divide the left operand by 2^n, where n is the right operand and the division truncation is done by ceiling. In other words, x ^>> n is equivalent to ceil(x / 2^n), where ceil is the ceil function, 2^n is exponentiation of 2 by n, and / is standard arithmetical division.
2 ^>> 1;       ;; 1,  since ceil(2 / 2^1) = 1
(- 2) ^>> 1;   ;; -1, since ceil(-2 / 2^1) = -1
8 ^>> 2;       ;; 2,  since ceil(8 / 2^2) = 2
5 ^>> 1;       ;; 3,  since ceil(5 / 2^1) = 3
(- 14) ^>> 2;  ;; -3  since ceil(-14 / 2^2) = -3

Rounding shift right, ~>>

The tilde-double greater than (rounding shift right) operator computes an efficient way to divide the left operand by 2^n, where n is the right operand and the division truncation is done by rounding half up. In other words, x ~>> n is equivalent to floor(x / 2^n + 0.5), where floor is the floor function, 2^n is exponentiation of 2 by n, / is standard arithmetical division, and + is standard arithmetical addition.
15 ~>> 3;       ;; 2,  since floor(15 / 2^3 + 0.5) = 2
12 ~>> 3;       ;; 2,  since floor(12 / 2^3 + 0.5) = 2
11 ~>> 3;       ;; 1,  since floor(11 / 2^3 + 0.5) = 1
(- 14) ~>> 3;   ;; -2, since floor(-14 / 2^3 + 0.5) = -2
(- 12) ~>> 3;   ;; -1  since floor(-12 / 2^3 + 0.5) = -1

Greater than, >

The greater than operator > returns -1 if the left operand is greater than the right operand and 0 otherwise.
2 > 2;          ;; 0
(- 1) > (- 3);  ;; -1

Greater than or equal, >=

The greater than or equal to operator >= returns -1 if the left operand is greater than or equal to the right operand and 0 otherwise.
2 >= 2;           ;; -1
(- 3) >= (- 1);   ;; 0

Less than, <

The less than operator < returns -1 if the left operand is less than the right operand and 0 otherwise.
2 < 2;           ;; 0
(- 3) < (- 1);   ;; -1

Less than or equal, <=

The less than or equal to operator <= returns -1 if the left operand is less than or equal to the right operand and 0 otherwise.
2 <= 2;           ;; -1
(- 1) <= (- 3);   ;; 0

Comparison, <=>

The less than or equal or greater than (comparison) operator <=>, returns -1 if the left operand is less than the right operand, 0 if the left and right operands are equal, or 1 if the left operand is greater than the right operand.
1 <=> 2;           ;; -1
(- 2) <=> (- 2);   ;; 0
2 <=> (- 1)        ;; 1

Equality, ==

The equality operator == checks whether its two operands are equal, returning -1 if they are and 0 otherwise. The == can only compare integers.
1 == 2;           ;; 0
(- 2) == (- 2);   ;; -1

Inequality, !=

The inequality operator != checks whether its two operands are different, returning -1 if they are and 0 otherwise. The != can only compare integers.
1 != 2;           ;; -1
(- 2) != (- 2);   ;; 0

Ternary, ?:

The conditional (ternary) operator ?: is the only operator that takes three operands: a condition followed by a question mark (?), then an expression to execute (the “consequent” expression) if the condition evaluates to an integer different from 0, followed by a colon (:), and finally the expression to execute (the “alternative” expression) if the condition evaluates to 0. This operator is frequently used as an alternative to an if...else statement.
<condition> ? <consequent expression> : <alternative expression>
Both the consequent and alternative expressions must have the same type. The condition must have the type integer.
2 ? 3 : 4;      ;; 3, since the condition evaluates to an integer different from 0
0 ? 3 : 4;      ;; 4, since the condition evaluates to 0
1 < 2 ? 3 : 4;  ;; 3, since the condition evaluates to -1
1 != 4 ? begin_cell() : 5;   ;; DOES NOT COMPILE: consequent and alternative do not have the same type

Assignment, =

The assignment operator = is used to assign the result of an expression to a variable. After execution, the = operator returns the value assigned to the variable.
a = 5;       ;; Assigns 5 to variable a, and returns 5
b = 5 + a;   ;; Assigns 10 to variable b, and returns 10
Since the assignment operator returns the assigned value, it can be used in expressions:
(a = 5) + 10;   ;; Assign 5 to a, and the expression evaluates to 15
(a = 5) + a;    ;; Assigns 5 to a, and the expression evaluates to 10,
                ;; since a = 5 evaluates to 5, and 5 + a is 10.
The operator = is right associative:
(b = a = 5) + b;   ;; Parses as (b = (a = 5)) + b.
                   ;; So, it does the following:
                   ;; (1) a = 5 assigns 5 to a, and returns 5. 
                   ;; (2) b = (a = 5) assigns 5 to b, and returns 5.
                   ;; (3) (b = (a = 5)) + b, evaluates to 10, since b has value 5.
                   ;; From here onwards, a and b have value 5.
The assignment operator can also occur in variable declarations, which are also expressions:
int x = 5;        ;; Declares integer variable x with value 5, and returns 5.
a = (int y = 5);  ;; Declares integer variable y with value 5, then assigns 5 to a, and returns 5.
                  ;; From here onwards, a has value 5 and y is also available with value 5.
(int z = 5) + z;  ;; Declares integer variable z with value 5, and the expression evaluates to 10,
                  ;; since after the declaration, z has value 5.
                  ;; From here onwards, z is available with value 5.

Augmented assignment operators

Augmented (or compound) assignment operators such as += combine an operation with an assignment. Augmented assignments are semantically equivalent to regular assignments = but include an operation:
a += 5;  
;; is equivalent to:
a = a + 5;
After execution, the augmented operator returns the final value assigned to the variable:
int a = 0; int b = 2;
a += 4;         ;; returns 4 and assigns 4 to a,  equivalent to a = a + 4.
b *= 10;        ;; returns 20 and assigns 20 to b, equivalent to b = b * 10.
(b /= 2) + 1;   ;; returns 11 and assigns 10 to b, equivalent to (b = b / 2) + 1.
List of augmented assignment operators:
I