Operators Reference
Every operator in Adama -- precedence, associativity, type compatibility, and examples. Most of this will feel familiar if you've used C, Java, or JavaScript. The interesting wrinkles are division returning maybe<T> (because division by zero is a thing) and the =? pattern match operator.
Operator Precedence
Operators listed from highest to lowest precedence. Higher precedence binds more tightly.
| Precedence | Operators | Description | Associativity |
|---|---|---|---|
| 1 | () [] . |
Grouping, indexing, member access | Left to right |
| 2 | ! - ++ -- |
Unary operators | Right to left |
| 3 | * / % |
Multiplicative | Left to right |
| 4 | + - |
Additive | Left to right |
| 5 | < <= > >= =? |
Relational | Left to right |
| 6 | == != |
Equality | Left to right |
| 7 | && |
Logical AND | Left to right |
| 8 | || |
Logical OR | Left to right |
| 9 | ?: |
Ternary conditional | Right to left |
| 10 | = += -= *= |
Assignment | Right to left |
Arithmetic Operators
Addition (+)
Adds two values or concatenates strings.
| Left Type | Right Type | Result Type | Description |
|---|---|---|---|
int |
int |
int |
Integer addition |
int |
long |
long |
Promoted to long |
int |
double |
double |
Promoted to double |
long |
long |
long |
Long addition |
long |
double |
double |
Promoted to double |
double |
double |
double |
Floating point addition |
string |
any | string |
String concatenation |
| any | string |
string |
String concatenation |
complex |
complex |
complex |
Complex addition |
vec2 |
vec2 |
vec2 |
Vector addition |
vec3 |
vec3 |
vec3 |
Vector addition |
vec4 |
vec4 |
vec4 |
Vector addition |
timespan |
timespan |
timespan |
Duration addition |
Examples:
int a = 5 + 3; // 8
double b = 5 + 3.14; // 8.14
string c = "Hello, " + "World!"; // "Hello, World!"
string d = "Count: " + 42; // "Count: 42"
vec3 v = @vec[1,0,0] + @vec[0,1,0]; // @vec[1,1,0]
Subtraction (-)
Subtracts the right operand from the left operand.
| Left Type | Right Type | Result Type | Description |
|---|---|---|---|
int |
int |
int |
Integer subtraction |
int |
long |
long |
Promoted to long |
int |
double |
double |
Promoted to double |
long |
long |
long |
Long subtraction |
long |
double |
double |
Promoted to double |
double |
double |
double |
Floating point subtraction |
complex |
complex |
complex |
Complex subtraction |
vec2 |
vec2 |
vec2 |
Vector subtraction |
vec3 |
vec3 |
vec3 |
Vector subtraction |
vec4 |
vec4 |
vec4 |
Vector subtraction |
timespan |
timespan |
timespan |
Duration subtraction |
Examples:
int a = 10 - 3; // 7
double b = 10.5 - 3.2; // 7.3
vec3 v = @vec[5,5,5] - @vec[1,2,3]; // @vec[4,3,2]
Multiplication (*)
Multiplies two values.
| Left Type | Right Type | Result Type | Description |
|---|---|---|---|
int |
int |
int |
Integer multiplication |
int |
long |
long |
Promoted to long |
int |
double |
double |
Promoted to double |
long |
long |
long |
Long multiplication |
long |
double |
double |
Promoted to double |
double |
double |
double |
Floating point multiplication |
string |
int |
string |
String repetition |
complex |
complex |
complex |
Complex multiplication |
vec2 |
vec2 |
double |
Dot product |
vec3 |
vec3 |
double |
Dot product |
vec4 |
vec4 |
double |
Dot product |
vec2 |
double |
vec2 |
Scalar multiplication |
vec3 |
double |
vec3 |
Scalar multiplication |
vec4 |
double |
vec4 |
Scalar multiplication |
double |
vec2 |
vec2 |
Scalar multiplication |
double |
vec3 |
vec3 |
Scalar multiplication |
double |
vec4 |
vec4 |
Scalar multiplication |
mat4 |
mat4 |
mat4 |
Matrix multiplication |
mat4 |
vec4 |
vec4 |
Matrix-vector multiplication |
math4 |
vec3 |
vec3 |
Homogeneous transformation |
timespan |
double |
timespan |
Duration scaling |
double |
timespan |
timespan |
Duration scaling |
Examples:
int a = 5 * 3; // 15
double b = 5.0 * 2.5; // 12.5
string c = "ha" * 3; // "hahaha"
double dot = @vec[1,0,0] * @vec[0,1,0]; // 0.0 (perpendicular)
vec3 scaled = @vec[1,2,3] * 2.0; // @vec[2,4,6]
Division (/)
Divides the left operand by the right operand.
Important: Division always returns
maybe<T>because division by zero is possible. I know it's a bit annoying to unwrap every time, but it beats a runtime crash.
| Left Type | Right Type | Result Type | Description |
|---|---|---|---|
int |
int |
maybe<double> |
Integer division |
int |
long |
maybe<double> |
Promoted division |
int |
double |
maybe<double> |
Promoted division |
long |
long |
maybe<double> |
Long division |
long |
double |
maybe<double> |
Promoted division |
double |
double |
maybe<double> |
Floating point division |
complex |
complex |
maybe<complex> |
Complex division |
Examples:
maybe<double> a = 10 / 3; // Contains ~3.333
maybe<double> b = 10 / 0; // Empty (division by zero)
// Safe usage with getOrDefaultTo
double result = (10 / 2).getOrDefaultTo(-1); // 5.0
double safe = (10 / 0).getOrDefaultTo(-1); // -1.0
int x = 10;
int y = 3;
@construct {
// Pattern matching
if ((x / y) as quotient) {
// quotient is a double
}
}
Modulo (%)
Returns the remainder after division.
Important: Modulo returns
maybe<T>because modulo by zero is undefined. Same logic as division.
| Left Type | Right Type | Result Type | Description |
|---|---|---|---|
int |
int |
maybe<int> |
Integer modulo |
long |
long |
maybe<long> |
Long modulo |
vec2 |
vec2 |
double |
2D cross product (scalar) |
vec3 |
vec3 |
vec3 |
3D cross product (vector) |
Examples:
maybe<int> a = 10 % 3; // Contains 1
maybe<int> b = 10 % 0; // Empty (modulo by zero)
int remainder = (17 % 5).getOrDefaultTo(0); // 2
// Cross product
vec3 cross = @vec[1,0,0] % @vec[0,1,0]; // @vec[0,0,1]
Unary Minus (-)
Negates a numeric value.
| Operand Type | Result Type | Description |
|---|---|---|
int |
int |
Integer negation |
long |
long |
Long negation |
double |
double |
Floating point negation |
complex |
complex |
Complex negation |
vec2 |
vec2 |
Vector negation |
vec3 |
vec3 |
Vector negation |
vec4 |
vec4 |
Vector negation |
Examples:
int a = -5; // -5
double b = -3.14; // -3.14
vec3 v = -@vec[1,2,3]; // @vec[-1,-2,-3]
Comparison Operators
Equality (==)
Returns true if operands are equal.
| Left Type | Right Type | Result Type |
|---|---|---|
int |
int |
bool |
long |
long |
bool |
double |
double |
bool |
bool |
bool |
bool |
string |
string |
bool |
principal |
principal |
bool |
label |
label |
bool |
date |
date |
bool |
time |
time |
bool |
datetime |
datetime |
bool |
asset |
asset |
bool |
| enum | same enum | bool |
Examples:
enum Status { Active, Inactive }
private principal owner;
private Status status;
bool a = (5 == 5); // true
bool b = ("hi" == "hi"); // true
@connected {
bool c = (@who == owner); // depends on context
bool d = (status == Status::Active); // enum comparison
return true;
}
Inequality (!=)
Returns true if operands are not equal.
Same type combinations as ==.
Examples:
bool a = (5 != 3); // true
bool b = ("hi" != "bye"); // true
@connected {
bool c = (@who != @no_one); // true if authenticated
return true;
}
Less Than (<)
Returns true if left operand is less than right operand.
| Left Type | Right Type | Result Type |
|---|---|---|
int |
int |
bool |
long |
long |
bool |
double |
double |
bool |
string |
string |
bool |
date |
date |
bool |
time |
time |
bool |
datetime |
datetime |
bool |
Examples:
bool a = (3 < 5); // true
bool b = (3.14 < 2.71); // false
bool c = ("apple" < "banana"); // true (lexicographic)
Less Than or Equal (<=)
Returns true if left operand is less than or equal to right operand.
Same type combinations as <.
Examples:
bool a = (3 <= 5); // true
bool b = (5 <= 5); // true
Greater Than (>)
Returns true if left operand is greater than right operand.
Same type combinations as <.
Examples:
bool a = (5 > 3); // true
bool b = (3.14 > 2.71); // true
Greater Than or Equal (>=)
Returns true if left operand is greater than or equal to right operand.
Same type combinations as <.
Examples:
bool a = (5 >= 3); // true
bool b = (5 >= 5); // true
Pattern Match (=?)
Returns true if the left string matches the right pattern. Glob-style matching.
| Left Type | Right Type | Result Type | Description |
|---|---|---|---|
string |
string |
bool |
Glob-style pattern matching |
Pattern Syntax:
*matches zero or more characters?matches exactly one character
Examples:
bool a = "hello" =? "hel*"; // true
bool b = "hello" =? "h*o"; // true
bool c = "hello" =? "h?llo"; // true
bool d = "hello" =? "world"; // false
bool e = "test.txt" =? "*.txt"; // true
Logical Operators
Logical AND (&&)
Returns true if both operands are true. Short-circuits: if the left operand is false, the right side never runs.
| Left Type | Right Type | Result Type |
|---|---|---|
bool |
bool |
bool |
Examples:
private principal user;
private principal owner;
bool a = true && true; // true
bool b = true && false; // false
bool c = false && true; // false (short-circuits)
@connected {
// Common pattern: guard checks
if (user != @no_one && user == owner) {
// Safe: second condition only evaluated if user is not @no_one
}
return true;
}
Logical OR (||)
Returns true if either operand is true. Short-circuits: if the left operand is true, the right side never runs.
| Left Type | Right Type | Result Type |
|---|---|---|
bool |
bool |
bool |
Examples:
bool isOwner = false;
bool isAdmin = false;
bool isPublic = true;
bool a = true || false; // true (short-circuits)
bool b = false || true; // true
bool c = false || false; // false
// Common pattern: default values
bool allowed = isOwner || isAdmin || isPublic;
Logical NOT (!)
Returns the logical inverse of the operand.
| Operand Type | Result Type |
|---|---|
bool |
bool |
Examples:
bool isBlocked = false;
bool isExpired = false;
bool a = !true; // false
bool b = !false; // true
bool c = !(5 > 3); // false
@construct {
// Common pattern: negation checks
if (!isBlocked && !isExpired) {
// Process request
}
}
Assignment Operators
Simple Assignment (=)
Assigns the right operand to the left operand.
Examples:
int x = 5;
string name = "Alice";
bool active = true;
Addition Assignment (+=)
Adds the right operand to the left operand and assigns the result.
Examples:
int x = 10;
string s = "Hello";
@construct {
x += 5; // x is now 15
s += " World"; // s is now "Hello World"
}
Subtraction Assignment (-=)
Subtracts the right operand from the left operand and assigns the result.
Examples:
int x = 10;
@construct {
x -= 3; // x is now 7
}
Multiplication Assignment (*=)
Multiplies the left operand by the right operand and assigns the result.
Examples:
int x = 5;
double d = 2.5;
@construct {
x *= 3; // x is now 15
d *= 2; // d is now 5.0
}
Increment and Decrement Operators
Prefix Increment (++x)
Increments the operand and returns the new value.
Examples:
int x = 5;
int y = ++x; // x is 6, y is 6
Postfix Increment (x++)
Returns the current value, then increments the operand.
Examples:
int x = 5;
int y = x++; // y is 5, x is 6
Prefix Decrement (--x)
Decrements the operand and returns the new value.
Examples:
int x = 5;
int y = --x; // x is 4, y is 4
Postfix Decrement (x--)
Returns the current value, then decrements the operand.
Examples:
int x = 5;
int y = x--; // y is 5, x is 4
Ternary Conditional Operator
Conditional Expression (? :)
Returns one of two values based on a condition.
Syntax: condition ? value_if_true : value_if_false
Examples:
int a = 5;
int b = 3;
bool isActive = true;
private principal player1;
private principal player2;
private principal current;
int max = (a > b) ? a : b;
string status = isActive ? "Active" : "Inactive";
principal next = (current == player1) ? player2 : player1;
Member Access Operators
Dot Operator (.)
Accesses a member of a record, object, or calls a method.
Examples:
record Name {
public string first;
}
record Profile {
public Name name;
}
record User {
public string name;
public Profile profile;
}
record Position {
public int x;
}
Position position;
User user;
string text = "hello";
maybe<int> value;
// Field access
public formula fx = position.x;
public formula fn = user.name;
// Method calls
public formula flen = text.length();
public formula fhas = value.has();
// Chained access
public formula first = user.profile.name.first;
Index Operator ([])
Accesses an element by index (arrays/lists) or key (maps).
Examples:
map<string, int> scores;
@construct {
// Map access
maybe<int> score = scores["Alice"];
}
Table Operators
Insert Operator (<-)
Inserts a new record into a table.
Examples:
record Player {
public string name;
public int score;
}
table<Player> _players;
record Msg {
public principal sender;
public string text;
public datetime timestamp;
}
table<Msg> _messages;
message ChatMsg {
string text;
}
channel chat(ChatMsg msg) {
_players <- {name: "Alice", score: 0};
_messages <- {sender: @who, text: msg.text, timestamp: Time.datetime()};
}
Type Summary
| Category | Operators |
|---|---|
| Arithmetic | + - * / % (unary -) |
| Comparison | == != < <= > >= =? |
| Logical | && || ! |
| Assignment | = += -= *= |
| Increment/Decrement | ++ -- |
| Conditional | ?: |
| Access | . [] |
| Table | <- |
Common Patterns
Safe Division
int numerator = 10;
int denominator = 3;
int a = 10;
int b = 3;
// Always handle the maybe result
double result = (numerator / denominator).getOrDefaultTo(0.0);
@construct {
// Or use pattern matching
if ((a / b) as quotient) {
// Use quotient safely
}
}
Compound Conditions
bool isActive = true;
bool isBlocked = false;
string role = "admin";
@construct {
// Check multiple conditions
if (isActive && !isBlocked && (role == "admin" || role == "owner")) {
// Allow action
}
}
Null-Safe Principal Checks
private principal owner;
@connected {
// Always check for @no_one before comparing principals
if (@who != @no_one && @who == owner) {
// User is authenticated and is the owner
}
return true;
}
String Building
string userName = "Alice";
int score = 100;
// Concatenate multiple values
string message = "User " + userName + " scored " + score + " points";
// Repeat strings
string separator = "-" * 20; // "--------------------"