Skip to content

Operators

EverSharp provides a comprehensive set of operators for arithmetic, comparison, logical operations, and more. This guide covers all operators with their precedence and usage patterns.


Operator Precedence

Operators are evaluated in the following order (highest to lowest precedence):

| Precedence | Operator | Description | Associativity | | ----------- | ---------------------------- | ------------------------------------- | ------------- | ---------- | ------------- | | 1 (highest) | () [] . | Grouping, array access, member access | Left-to-right | | 2 | ++ -- | Postfix increment/decrement | N/A | | 3 | ! - | Logical NOT, unary minus | Right-to-left | | 4 | * / % | Multiplication, division, modulo | Left-to-right | | 5 | + - | Addition, subtraction | Left-to-right | | 6 | < > <= >= | Comparison | Left-to-right | | 7 | == != | Equality | Left-to-right | | 8 | && | Logical AND | Left-to-right | | 9 | | | | Logical OR | Left-to-right | | 10 | ?: | Ternary conditional | Right-to-left | | 11 (lowest) | = += -= *= /= %= | Assignment | Right-to-left |


Arithmetic Operators

Addition +

// Numeric addition
sum = 10 + 20; // 30
total = price + tax; // Adds two numbers

// String concatenation
greeting = "Hello, " + "World"; // "Hello, World"
message = "Age: " + 30; // "Age: 30" (number converts to string)

Special behavior: If either operand is a string, performs concatenation.

Subtraction -

difference = 50 - 20; // 30
remaining = balance - withdrawal;
negative = 10 - 15; // -5

Multiplication *

product = 6 * 7; // 42
area = width * height;
double = value * 2;

Division /

quotient = 100 / 4; // 25
half = value / 2;
rate = premium / coverage; // 0.01 if premium=1000, coverage=100000

// Division by zero
// result = 10 / 0;             // RuntimeException

Modulo %

Returns the remainder of division:

remainder = 17 % 5; // 2
isEven = number % 2 == 0; // true if even
lastDigit = number % 10;

Use cases:

  • Check even/odd: x % 2 == 0
  • Cycle through values: index % arrayLength
  • Extract digits: number % 10

Unary Minus -

Negates a number:

negative = -42; // -42
opposite = -value;
negated = -(10 + 5); // -15

Comparison Operators

All comparison operators return boolean values.

Less Than <

10 < 20; // true
age < minAge; // true if age is less than minAge
"apple" < "banana"; // true (lexicographic)

Greater Than >

20 > 10; // true
premium > maxPremium; // true if premium exceeds maximum
"zebra" > "apple"; // true

Less Than or Equal <=

10 <= 10; // true
10 <= 20; // true
age <= 65; // true if age is 65 or less

Greater Than or Equal >=

20 >= 20; // true
20 >= 10; // true
age >= 18; // true if age is 18 or more

Equal ==

10 == 10; // true
"hello" == "hello"; // true
true == true; // true
null == null; // true

// No type coercion
10 == "10"; // false (different types)
true == 1; // false

Not Equal !=

10 != 20; // true
"hello" != "world"; // true
status != null; // true if status is not null

Comparison Examples

// Numeric comparison
age = 25;
isYoung = age < 30; // true
isSenior = age >= 65; // false

// String comparison (lexicographic)
name = "Bob";
comesFirst = name < "Charlie"; // true
isAlice = name == "Alice"; // false

// Date comparison
today = $Today();
future = $AddDays(today, 7);
isPast = today > future; // false
isFuture = future > today; // true

// Null comparison
value = null;
isEmpty = value == null; // true
hasValue = value != null; // false

Logical Operators

Logical AND &&

Returns true only if both operands are true:

true && true; // true
true && false; // false
false && false; // false

// Practical examples
isEligible = age >= 18 && hasLicense;
canProceed = !hasErrors && dataValid && userConfirmed;

Short-circuit evaluation: If left side is false, right side is NOT evaluated:

// Safe: person.age only accessed if person is not null
if (person != null && person.age > 18) {
  // ...
}

// Optimization: expensive check only if needed
if (quickCheck && expensiveFunction()) {
  // expensiveFunction() only called if quickCheck is true
}

Logical OR ||

Returns true if at least one operand is true:

true || false; // true
false || true; // true
false || false; // false

// Practical examples
isValid = hasEmail || hasPhone;
needsReview = isHighRisk || isLargeAmount || hasSpecialConditions;

Short-circuit evaluation: If left side is true, right side is NOT evaluated:

// Default value pattern
useDefault = config == null || config.value == null;

// Skip expensive check if simple check passes
if (isCached || loadFromDatabase()) {
  // loadFromDatabase() only called if NOT cached
}

Logical NOT !

Inverts a boolean value:

!true; // false
!false; // true

// Practical examples
isInactive = !isActive;
hasErrors = !isValid;
isEmpty = !(array.Length > 0);

// Double negation (convert to boolean, rarely needed in EverSharp)
!!value; // Same as value if already boolean

Combining Logical Operators

// Complex conditions
isEligible =
  age >= 18 && age <= 65 && (hasLicense || hasPermit) && !isBlacklisted;

// With parentheses for clarity
qualified =
  (income > 50000 || hasAssets) && creditScore > 650 && !hasBankruptcy;

// De Morgan's laws
!(a && b); // Equivalent to: !a || !b
!(a || b); // Equivalent to: !a && !b

Assignment Operators

Simple Assignment =

x = 10;
name = "John";
active = true;

// Assignment returns the value
a = b = c = 10; // All set to 10 (right-to-left)

Compound Assignment

Add-Assign +=

x = 10;
x += 5; // x = 15 (equivalent to: x = x + 5)

// String concatenation
message = "Hello";
message += " World"; // "Hello World"

// Common pattern
total += itemPrice;

Subtract-Assign -=

balance = 1000;
balance -= 250; // balance = 750

remaining -= used;

Multiply-Assign *=

value = 100;
value *= 1.5; // value = 150

premium *= adjustmentFactor;

Divide-Assign /=

amount = 1000;
amount /= 4; // amount = 250

average /= count;

Modulo-Assign %=

value = 17;
value %= 5; // value = 2

index %= arrayLength; // Keep index within bounds

Postfix Operators

Post-Increment ++

Returns current value, then increments:

counter = 5;
old = counter++; // old = 5, counter = 6

// Common in loops
i = 0;
while (i < 10) {
  $Log(i);
  i++; // Increment after each iteration
}

Post-Decrement --

Returns current value, then decrements:

counter = 5;
old = counter--; // old = 5, counter = 4

remaining--; // Decrease by 1

Note: No prefix versions (++x or --x) exist in EverSharp.


Ternary Operator ?:

Conditional expression: condition ? valueIfTrue : valueIfFalse

// Simple conditional
age = 20;
status = age >= 18 ? "Adult" : "Minor"; // "Adult"

// Assign different values
discount = isPremium ? 0.2 : 0.1;

// In calculations
premium = basePremium * (age > 65 ? 1.25 : 1.0);

// With expressions
max = a > b ? a : b;
min = a < b ? a : b;

// Nested (use sparingly for readability)
rate = age < 25 ? 0.15 : age < 65 ? 0.1 : 0.12;

// Better: use if-else for complex logic
if (age < 25) {
  rate = 0.15;
} else if (age < 65) {
  rate = 0.1;
} else {
  rate = 0.12;
}

Member Access Operator .

Accesses object properties or calls methods:

// Property access
name = person.name;
premium = policy.premium;

// Nested access
city = customer.address.city;

// Method calls
upper = text.ToUpper();
filtered = array.Filter((x) => x > 10);

// Assignment
person.age = 31;
policy.status = "active";

Array Access Operator []

Accesses array elements by index:

numbers = [10, 20, 30, 40, 50];

// Read
first = numbers[0]; // 10
third = numbers[2]; // 30

// Write
numbers[1] = 99; // [10, 99, 30, 40, 50]

// Dynamic index
index = 3;
value = numbers[index]; // 40

// Last element
last = numbers[numbers.Length - 1]; // 50

Grouping Operator ()

Overrides default precedence:

// Without parentheses (multiplication first)
result = 2 + 3 * 4; // 14

// With parentheses (addition first)
result = (2 + 3) * 4; // 20

// Complex expressions
average = (a + b + c) / 3;
adjusted = base * rate + fee;

// Logical grouping
if ((age >= 18 && age <= 25) || hasSpecialPermit) {
  // ...
}

Operator Precedence Examples

Example 1: Arithmetic

// Without parentheses
result = 2 + 3 * 4; // 14 (multiply first)
result = 10 - 2 + 3; // 11 (left-to-right)
result = (10 / 2) * 3; // 15 (left-to-right)

// With parentheses
result = (2 + 3) * 4; // 20
result = 10 - (2 + 3); // 5
result = 10 / (2 * 3); // 1.666...

Example 2: Comparison and Logical

// Comparison before logical
result = x > 5 && y < 10; // Comparisons evaluated first

// Requires parentheses for clarity
result = x > 5 && y < 10; // Same, but clearer

// AND before OR
result = a || (b && c); // Equivalent to: a || (b && c)
result = (a || b) && c; // Different: both a or b, AND c

Example 3: Assignment

// Assignment has lowest precedence
x = y + 5; // Addition first, then assignment

// Compound assignment
x += y * 2; // Equivalent to: x = x + (y * 2)

// Chained assignment (right-to-left)
a = b = c = 10; // c=10, then b=10, then a=10

Example 4: Complex Expression

// Step-by-step evaluation
result = 10 + 5 * 2 - 3 / 3;

// Order of operations:
// 1. 5 * 2 = 10
// 2. 3 / 3 = 1
// 3. 10 + 10 = 20
// 4. 20 - 1 = 19
// Result: 19

// With parentheses for different result
result = ((10 + 5) * 2 - 3) / 3; // ((15) * 2 - 3) / 3 = 27 / 3 = 9

Common Patterns

Pattern 1: Range Checking

// Check if value is in range
inRange = value >= min && value <= max;
inRange = $IsInRange(value, min, max); // Built-in function

// Check if outside range
outOfRange = value < min || value > max;

Pattern 2: Null-Safe Access

// Check null before accessing
if (object != null && object.property != null) {
  value = object.property.value;
}

// Default value pattern
displayName = name != null ? name : "Unknown";

Pattern 3: Clamping Values

// Clamp to range using ternary
clamped = value < min ? min : value > max ? max : value;

// Using $Max and $Min
clamped = $Min($Max(value, min), max);

Pattern 4: Flag Checking

// Check multiple flags
allSet = flag1 && flag2 && flag3;
anySet = flag1 || flag2 || flag3;
noneSet = !flag1 && !flag2 && !flag3;

// Toggle flag
flag = !flag;

Pattern 5: Conditional Accumulation

total = 0;
total += baseAmount;
total += includeTax ? taxAmount : 0;
total += includeShipping ? shippingCost : 0;
total -= hasDiscount ? discountAmount : 0;

Type Requirements

Different operators have different type requirements:

| Operator | Allowed Types | Result Type | | ----------------- | ----------------------------- | ---------------- | ----------------- | ------- | | + | number + number, string + any | number or string | | - * / % | number + number | number | | < > <= >= | same types | boolean | | == != | any types | boolean | | && | | ! | boolean + boolean | boolean | | = += etc. | any (matching) | assigned type |

Type errors:

// ERROR: Cannot multiply string and number
result = "5" * 10;

// CORRECT: Convert first
result = "5".ToNumber() * 10; // 50

// ERROR: Cannot use number as boolean
// if (count) { }

// CORRECT: Compare explicitly
if (count > 0) {
}

Best Practices

  1. Use parentheses for clarity: Even when not required
// Less clear
result = a + b * c - d / e;

// More clear
result = a + b * c - d / e;
  1. Avoid complex nested ternaries: Use if-else instead
// Hard to read
value = a ? (b ? c : d) : e ? f : g;

// Better
if (a) {
  value = b ? c : d;
} else {
  value = e ? f : g;
}
  1. Check for null before property access:
if (object != null && object.property != null) {
  // Safe to access
}
  1. Use compound assignment for clarity:
// Prefer
total += value;

// Over
total = total + value;
  1. Be explicit with boolean conditions:
// Prefer
if (count > 0) {
}
if (name != null && name != "") {
}

// Over (would be errors in EverSharp anyway)
// if (count) { }
// if (name) { }

Next Steps