Operators - cyxigo/wi GitHub Wiki
Introduction
Operators let you do specific operations on a pair of values (or a single value) and result in a new value. By now (if you read everything in order) you've seen two operators: = and []. But there are way more! Let's go through each category.
[!NOTE] If you thought about
:=, well, technically it's a statement, not an operator!
Expressions
Before we start, we need to talk about something called expressions. Every value itself and the results of operators are expressions, so:
[1, 2, 3]– this is array literal expression.1.0– this is real literal expression.2 + 2– this is binary term expression.f()– this is call expression.
This works with any value type, including functions and objects (we haven't talked about them yet but remember this part) too.
Assignment
As you've read in Variables, this operator modifies the variable.
a := 10;
a = 20; %% a is now 20
Arithmetic
10 + 5; %% 15 (addition)
10 - 5; %% 5 (subtraction)
10 * 5; %% 50 (multiplication)
10 / 5; %% 2 (division)
10 // 3; %% 3 (integer division)
10 % 3; %% 1 (modulo – calculates the remainder of the division)
2 ** 3; %% 8 (power)
%% Comparison
10 == 10; %% true (is equal to)
10 != 10; %% false (is NOT equal to)
1 > 2; %% false (greater than)
2 >= 2; %% true (greater than OR equal to)
1 < 2; %% true (less than)
2 <= 2; %% true (less than OR equal to)
[!NOTE] If you're coming from Python or Lua, Wi's
//and%behavior might confuse you because in Wi – they behave the same as in C, i.e. they truncate the result rather than floor it.
Logical
&& means logical AND – the result is truthy if and only if both operands are truthy.
true && false; %% false
true && true; %% true
false && true; %% false
false && false; %% false
|| means logical OR – the result is truthy if and only if at least one of operands is truthy.
true || false; %% true
true || true; %% true
false || true; %% true
false || false; %% false
! means logical NOT – the result is the opposite of the operand. If operand is truthy, result is falsy, if operand is falsy, result is truthy.
!true; %% false
!false; %% true
!0; %% true
!1; %% false
These operators work on comparison expressions because comparison results in a boolean value:
!(10 == 10); %% false
!(10 != 10); %% true
(1 > 2) && (2 >= 2); %% false
(1 < 2) || (2 <= 2); %% true
It is worth mentioning that in Wi you can check falsiness of every value type. null, 0 and false is falsy – everything else is truthy.
Bitwise
Bitwise operators work on the binary representation of numbers. They operate on the individual bits (0s and 1s). I won't talk much about binary math here because you should know or should learn about it yourself – it isn't that important to Wi programming.
5 | 3; %% 7 (bitwise OR)
5 ^ 3; %% 6 (bitwise XOR)
5 & 3; %% 1 (bitwise AND)
5 << 1; %% 10 (bitwise left shift)
5 >> 1; %% 2 (bitwise right shift)
~5; %% -6 (bitwise NOT)
Length
Length operator # is used to get the length of an indexable value (strings, arrays, and maps):
std::puts(#[1, 2, 3]); %% 3
std::puts(#"string"); %% 6
std::puts(#{ "x": 10, "y": 20 }); %% 2
Call
Call operator () is used to call functions. We'll talk about them soon. It accepts arguments separated by ,:
my_function(arg1, arg2);
Subscript
Subscript operator [] is used to access elements of collections – strings, arrays and maps.
[1, 2, 3][0]; %% 1
"Hello"[0]; %% H
{ "x": 10 }["x"]; %% 10
Module access
Module access operator :: is used to access exported variables from a module.
%% module.wi
x := 20;
export {
x
};
%% main.wi
module := import "module";
std::puts(module::x); %% 20
Field
The field operator . is used to access fields of an object.
obj.x = 10;
obj.x; %% 10
Invoke
The invocation operator -> is used to call a method on an object and pass object as the first argument. So instead of:
obj.method(obj, argument);
You write:
obj->method(argument);
It also works with built-in types:
"string"->sub(1, 4); %% tri
[10]->count(); %% 1
{ "a": 1, "b": 2 }->keys(); %% ["a", "b"]
Everything about objects and methods will make more sense later after you read about them.
new
The new operator is used to clone an object. It creates a new object that is a copy of the original.
obj_person := object {
name: "";
};
alice := new obj_person {
name: "Alice";
};
bob := new obj_person {
name: "Bob";
};
std::puts(alice.name); %% Alice
std::puts(bob.name); %% Bob
new is essential for Wi's prototype-based OOP. We'll talk more about OOP and the objects later.
Full precedence table, from tightest to loosest:
| Precedence | Operator | Description | Associativity |
|---|---|---|---|
| 1 | a() |
Function call | Left-to-right → |
a[] |
Subscript | ||
a::b |
Module access | ||
a.b |
Field access | ||
a->b() |
Method invocation | ||
| 2 | #a |
Length | Right-to-left ← |
-a |
Negation | ||
~a |
Bitwise NOT | ||
!a |
Logical NOT | ||
new a/new a, b |
Cloning/Merging | ||
| 3 | a ** b |
Power | Right-to-left ← |
| 4 | a * b |
Multiplication | Left-to-right → |
a / b |
Division | ||
a // b |
Integer division | ||
a % b |
Modulo | ||
| 5 | a + b |
Addition | Left-to-right → |
a - b |
Subtraction | ||
| 6 | a >> b |
Bitwise right shift | Left-to-right → |
a << b |
Bitwise left shift | ||
| 7 | a & b |
Bitwise AND | Left-to-right → |
| 8 | a ^ b |
Bitwise XOR | Left-to-right → |
| 9 | a | b |
Bitwise OR | Left-to-right → |
| 10 | a > b |
Greater than | Left-to-right → |
a >= b |
Greater than or equal | ||
a < b |
Less than | ||
a <= b |
Less than or equal | ||
| 11 | a == b |
Equality | Left-to-right → |
a != b |
Inequality | ||
| 12 | a && b |
Logical AND | Left-to-right → |
| 13 | a || b |
Logical OR | Left-to-right → |
| 14 | a = b |
Assignment | Right-to-left ← |
Next: Control Flow