Operators

Operators are special symbols that perform operations on operands. Dart supports a rich set of operators for various operations.

Arithmetic Operators

int a = 10, b = 3;

print(a + b);   // 13 - Addition
print(a - b);   // 7  - Subtraction
print(a * b);   // 30 - Multiplication
print(a / b);   // 3.333... - Division (returns double)
print(a ~/ b);  // 3  - Integer division
print(a % b);   // 1  - Modulo (remainder)

// Unary operators
print(-a);      // -10 - Negation

Increment and Decrement

int x = 5;

print(++x);  // 6 - Pre-increment (increment then return)
print(x++);  // 6 - Post-increment (return then increment)
print(x);    // 7

print(--x);  // 6 - Pre-decrement
print(x--);  // 6 - Post-decrement
print(x);    // 5

Equality and Relational Operators

int a = 10, b = 20;

print(a == b);   // false - Equal to
print(a != b);   // true  - Not equal to
print(a > b);    // false - Greater than
print(a < b);    // true  - Less than
print(a >= b);   // false - Greater than or equal to
print(a <= b);   // true  - Less than or equal to

Logical Operators

bool a = true, b = false;

print(a && b);   // false - AND
print(a || b);   // true  - OR
print(!a);       // false - NOT

Assignment Operators

int a = 10;

a += 5;   // a = a + 5  (15)
a -= 3;   // a = a - 3  (12)
a *= 2;   // a = a * 2  (24)
a ~/= 4;  // a = a ~/ 4 (6)
a %= 4;   // a = a % 4  (2)

Type Test Operators

var value = 'Hello';

print(value is String);      // true
print(value is! int);        // true
print(value is Object);      // true

// Type cast
dynamic obj = 'Hello';
String str = obj as String;  // Cast to String

Bitwise Operators

int a = 5;   // 0101 in binary
int b = 3;   // 0011 in binary

print(a & b);   // 1  (0001) - AND
print(a | b);   // 7  (0111) - OR
print(a ^ b);   // 6  (0110) - XOR
print(~a);      // -6 - NOT (inverts bits)
print(a << 1);  // 10 (1010) - Left shift
print(a >> 1);  // 2  (0010) - Right shift

Conditional Expressions

Ternary Operator

int age = 18;
String status = age >= 18 ? 'Adult' : 'Minor';
print(status);  // Adult

Null-coalescing Operator

String? name;
String displayName = name ?? 'Guest';
print(displayName);  // Guest

// Assign if null
name ??= 'Default';
print(name);  // Default

Cascade Notation

Allows you to perform a sequence of operations on the same object:

class Person {
  String? name;
  int? age;
  
  void introduce() {
    print('I am $name, $age years old');
  }
}

void main() {
  Person person = Person()
    ..name = 'Alice'
    ..age = 25
    ..introduce();  // I am Alice, 25 years old
  
  // Null-aware cascade
  Person? nullablePerson;
  nullablePerson?..name = 'Bob'..age = 30;
}

Spread Operator

List<int> list1 = [1, 2, 3];
List<int> list2 = [4, 5, 6];

// Spread operator
List<int> combined = [...list1, ...list2];
print(combined);  // [1, 2, 3, 4, 5, 6]

// Null-aware spread
List<int>? nullableList;
List<int> safe = [...?nullableList, 7, 8];
print(safe);  // [7, 8]

Null-aware Operators

Null-aware Access

class Person {
  String? name;
}

Person? person;

// Safe navigation
print(person?.name);  // null (no error)

// Chaining
print(person?.name?.length);  // null

Null-aware Assignment

String? name;
name ??= 'Default';  // Assign only if null
print(name);  // Default

name ??= 'Another';  // Won't assign (name is not null)
print(name);  // Default

Null Assertion

String? nullable = 'Hello';
String nonNull = nullable!;  // Assert non-null
print(nonNull);  // Hello

// Throws error if null
String? nullValue;
// String error = nullValue!;  // Error: Null check operator used on a null value

Index Operator

List<int> numbers = [10, 20, 30, 40];
print(numbers[0]);  // 10
print(numbers[2]);  // 30

Map<String, int> ages = {'Alice': 25, 'Bob': 30};
print(ages['Alice']);  // 25

Operator Precedence

From highest to lowest:

  1. Postfix: expr++, expr--, (), [], ., ?.
  2. Unary prefix: -expr, !expr, ~expr, ++expr, --expr
  3. Multiplicative: *, /, %, ~/
  4. Additive: +, -
  5. Shift: <<, >>
  6. Bitwise AND: &
  7. Bitwise XOR: ^
  8. Bitwise OR: |
  9. Relational: >=, >, <=, <, as, is, is!
  10. Equality: ==, !=
  11. Logical AND: &&
  12. Logical OR: ||
  13. Null-aware: ??
  14. Conditional: expr1 ? expr2 : expr3
  15. Cascade: .., ?..
  16. Assignment: =, *=, /=, +=, -=, etc.

Operator Overloading

You can override operators in custom classes:

class Vector {
  final double x, y;
  
  Vector(this.x, this.y);
  
  // Overload + operator
  Vector operator +(Vector other) {
    return Vector(x + other.x, y + other.y);
  }
  
  // Overload - operator
  Vector operator -(Vector other) {
    return Vector(x - other.x, y - other.y);
  }
  
  // Overload * operator (scalar multiplication)
  Vector operator *(double scalar) {
    return Vector(x * scalar, y * scalar);
  }
  
  @override
  String toString() => 'Vector($x, $y)';
}

void main() {
  Vector v1 = Vector(3, 4);
  Vector v2 = Vector(1, 2);
  
  print(v1 + v2);  // Vector(4.0, 6.0)
  print(v1 - v2);  // Vector(2.0, 2.0)
  print(v1 * 2);   // Vector(6.0, 8.0)
}

Best Practices

  1. Use parentheses to make complex expressions clearer
  2. Prefer ?? over explicit null checks when providing defaults
  3. Use cascade notation for multiple operations on the same object
  4. Be careful with ! - only use when you're certain the value isn't null
  5. Use ?. for safe navigation through potentially null objects

Complete Example

class Calculator {
  double? lastResult;
  
  double calculate(double a, double b, String operator) {
    lastResult = switch (operator) {
      '+' => a + b,
      '-' => a - b,
      '*' => a * b,
      '/' => b != 0 ? a / b : 0,
      _ => 0,
    };
    return lastResult!;
  }
  
  void reset() => lastResult = null;
}

void main() {
  Calculator calc = Calculator()
    ..calculate(10, 5, '+')
    ..calculate(20, 4, '*');
  
  print('Last result: ${calc.lastResult}');  // 80.0
  
  // Null-aware operations
  String? input;
  String display = input ?? 'No input';
  print(display);  // No input
  
  // Conditional expression
  int age = 25;
  String category = age >= 18 ? 'Adult' : 'Minor';
  print('Category: $category');  // Adult
  
  // Spread operator
  List<int> numbers1 = [1, 2, 3];
  List<int> numbers2 = [4, 5, 6];
  List<int> all = [...numbers1, ...numbers2];
  print('All numbers: $all');  // [1, 2, 3, 4, 5, 6]
}

Next Steps