Operators & Expressions — Working With Values
Operators are the verbs of a programming language: they take values and
produce new ones. AdeshLang has a full, expressive operator set —
arithmetic, comparison, logical, nullish, bitwise, and more — demonstrated in
examples/syntax/operators.adesh.
Arithmetic
let a = 10;
let b = 3;
print(a + b); // addition
print(a - b); // subtraction
print(a * b); // multiplication
print(a / b); // division
print(a % b); // modulo (remainder)
print(2 ** 8); // power
print(7 ~/ 3); // integer (truncated) division
Output:
13
7
30
3.3333333333333335
1
256
2
Comparison
let a = 10;
let b = 3;
print(a == b, a != b, a > b, a >= b, a < b, a <= b);
Output:
false true true true false false
Loose == vs strict ===
== compares values (allowing type coercion); === also requires the same
type. This comes from
examples/operators/strict_equality.adesh:
let a = 2;
let b = "2";
print("typeof a:", typeof a); // number
print("typeof b:", typeof b); // string
print("a==b:", a == b); // true (values match)
print("a===b:", a === b); // false (types differ)
let s1 = "hello";
let s2 = "hello";
print("s1==s2:", s1 == s2); // true
print("s1===s2:", s1 === s2); // true (same type AND value)
Output:
typeof a: number
typeof b: string
a==b: true
a===b: false
s1==s2: true
s1===s2: true
Arrays and objects compare by reference with ===, by content with ==:
let x = [1];
let y = [1];
let z = &x;
print("x==y:", x == y); // true (same content)
print("x===y:", x === y); // false (different arrays)
print("x===z:", x === z); // true (z points at x)
Output:
x==y: true
x===y: false
x===z: true
Logical operators
print(true && false); // AND
print(true || false); // OR
print(!false); // NOT
print((!false) && (true || false)); // combined
Output:
false
true
true
true
Nullish coalescing ??
?? picks the value on the right only when the left is null — never
for 0, false, or "". From
examples/syntax/test_nullish_coalescing.adesh:
let n = null;
print(n ?? 42); // null → use 42
let zero = 0;
print(zero ?? 99); // 0 is a real value → stays 0
let a = null;
let b = null;
let c = 100;
print(a ?? b ?? c); // chains: 100
let keep = "existing";
keep ??= "set-on-null"; // only assigns if null
print(keep);
Output:
42
0
100
existing
Optional chaining ?.
?. safely reads nested fields even when an intermediate value is null.
From
examples/syntax/test_optional_chaining.adesh:
let obj = { user: { name: "Alice", age: 30 } };
print(obj?.user?.name); // Alice
let nullObj = null;
print(nullObj?.field); // null, no crash!
let deep = { a: { b: { c: 42 } } };
print(deep?.a?.b?.c); // 42
Output:
Alice
null
42
Spread ... and ranges
let arr = [1, 2, 3];
let arr2 = [...arr, 4, 5];
print(arr2); // spread copies elements
let rng = 1 .. 5; // half-open range (excludes end)
let rngi = 1 ... 5; // inclusive range
print(rng, rngi);
Output:
[1, 2, 3, 4, 5]
[1, 2, 3, 4] [1, 2, 3, 4, 5]
Bitwise, membership, and typeof
print(6 & 3); // AND → 2
print(6 | 1); // OR → 7
print(6 ^ 5); // XOR → 3
print(1 << 4); // shift left → 16
print(16 >> 2); // shift right → 4
print(2 in [1, 2, 3]); // membership in array
print("a" in { a: 1 }); // membership in object
print("llo" in "hello"); // substring check
print(typeof(123), typeof("abc"));
Output:
2
7
3
16
4
true
true
true
number string
Ternary, arrow functions, and updates
let cond = true;
print(cond ? "yes" : "no"); // ternary
let inc = x => x + 1; // arrow function
print(inc(10));
let ux = 1;
ux++; // increment
let uy = 5;
--uy; // decrement
print(ux, uy);
Output:
yes
11
2 4
Type-level operators | and ? (DSA new syntax)
Not runtime ops but type operators — documented here because they appear beside ??/?.:
fn findIndex(nums: [int], target: int): int | null { ... } // union
fn getTopWord(freq: dict): string | null { ... }
fn describeValue(v: int | string | bool): string { ... } // multi-union
let x: int? = null; // T? == T | null (postfix)
type Node = { data: int, next: Node? };
type User = { name: String, age?: u8 = 20 }; // optional field with default
type Box<T> = { value: T, tag?: String = "generic-box" };
print(typeof(x)); // "int?" — nullable type tag
A | B— union type;[]/{}are valid members ([int] | [])T?— postfix optional;field?: T— optional field; with= defaultfor injection- Always written with colon
:return (fn f(): T | null), never->(onlyextern "C"uses->)
Container + set operators
let s: set; s.insert(1); s.insert(2); // default decl
let sA = Set([1, 2, 3]); let sB = Set([3, 4]);
print(sA.union(sB)); // {1,2,3,4}
print(sA.intersection(sB)); // {3}
print(sA.contains(2)); // true
print(2 in [1, 2, 3]); // true (membership)
print("llo" in "hello"); // true
Practice
Write operators_work.adesh and predict each line before you run it:
let price = 120;
let discount = 0.2;
let final = price * (1 - discount);
print(final);
let user = { profile: { email: "a@b.c" } };
print(user?.profile?.phone ?? "no phone");
let tags = ["core", ...(price > 100 ? ["premium"] : [])];
print(tags);
Output:
96
no phone
[core, premium]
Summary
✅ You learned:
- Arithmetic:
+ - * / % ** ~/ - Comparison:
==vs===,!=,< > <= >= - Logical:
&&,||,! ??for null defaults and??=for safe assignment?.for safe nested access...spread,../...ranges- bitwise ops,
inmembership,typeof - ternary
?:, arrow functions,++/--
Next Step
Now put these expressions to work making decisions with conditionals. Continue to Conditionals →