Operators

Domains: Dart

Dart defines the operators shown in the following table. You can override many of these operators, as described in Overridable operators.

unary postfix
expr++    expr--    ()    []    .    ?.
unary prefix
-expr    !expr    ~expr    ++expr    --expr      await expr
multiplicative
*    /    %  ~/
additive
+    - 
shift
<<    >>    >>>
bitwise AND
bitwise XOR
^
bitwise OR
relational and type test
>=    >    <=    <    as    is    is! 
equality
==    != 
logical AND
&&
logical OR
|| 
if null
?? 
conditional
expr1 ? expr2 : expr3 
cascade
.. 
assignment
=    *=    /=   +=   -=   &=   ^=   etc.

Warning: Operator precedence is an approximation of the behavior of a Dart parser. 

When you use operators, you create expressions. Here are some examples of operator expressions:

a++
a + b
a = b
a == b
c ? a : b
a is T 

In the operator table, each operator has higher precedence than the operators in the rows that follow it. For example, the multiplicative operator % has higher precedence than (and thus executes before) the equality operator ==, which has higher precedence than the logical AND operator &&. That precedence means that the following two lines of code execute the same way:

// Parentheses improve readability. 
if ((n % i == 0) && (d % i == 0)) ... 

// Harder to read, but equivalent. 
if (n % i == 0 && d % i == 0) ...

Warning: For operators that work on two operands, the leftmost operand determines which version of the operator is used. For example, if you have a Vector object and a Point object, aVector + aPoint uses the Vector version of +.

Arithmetic operators

Dart supports the usual arithmetic operators, as shown in the following table.

+
Add 
Subtract 
-expr  
Unary minus, also known as negation (reverse the sign of the expression)
*
Multiply 
/
Divide 
~/
Divide, returning an integer result 
%
Get the remainder of an integer division (modulo)

Example:

assert(2 + 3 == 5); 
assert(2 - 3 == -1); 
assert(2 * 3 == 6); 
assert(5 / 2 == 2.5); // Result is a double 
assert(5 ~/ 2 == 2); // Result is an int 
assert(5 % 2 == 1); // Remainder 

assert('5/2 = ${5 ~/ 2} r ${5 % 2}' == '5/2 = 2 r 1'); 

Dart also supports both prefix and postfix increment and decrement operators.

++var
var = var + 1 (expression value is var + 1)
var++
var = var + 1 (expression value is var)
--var
var = var – 1 (expression value is var – 1)
var--
var = var – 1 (expression value is var)

Example:

var a, b; 

a = 0; 
b = ++a; // Increment a before b gets its value. 
assert(a == b); // 1 == 1 

a = 0; 
b = a++; // Increment a AFTER b gets its value. 
assert(a != b); // 1 != 0 

a = 0; 
b = --a; // Decrement a before b gets its value. 
assert(a == b); // -1 == -1 

a = 0; 
b = a--; // Decrement a AFTER b gets its value. 
assert(a != b); // -1 != 0

Equality and relational operators

The following table lists the meanings of equality and relational operators.

==
Equal
!=
Not equal
>
Greater than
<
Less than
>=
Greater than or equal to 
<=
Less than or equal to

To test whether two objects x and y represent the same thing, use the == operator. (In the rare case where you need to know whether two objects are the exact same object, use the identical() function instead.) Here’s how the == operator works:

If x or y is null, return true if both are null, and false if only one is null.

Return the result of the method invocation x.==(y).

(That’s right, operators such as == are methods that are invoked on their first operand. You can even override many operators as you’ll see in Overridable operators.)

Here’s an example of using each of the equality and relational operators:

assert(2 == 2);
assert(2 != 3);
assert(3 > 2);
assert(2 < 3);
assert(3 >= 3);
assert(2 <= 3);

Type test operators

The as, is, and is! operators are handy for checking types at runtime.

as
Typecast (also used to specify library prefixes)
is
True if the object has the specified type
is!
False if the object has the specified type

The result of obj is T is true if obj implements the interface specified by T. For example, obj is Object is always true.

Use the as operator to cast an object to a particular type. In general, you should use it as a shorthand for an is test on an object followed by an expression using that object. For example, consider the following code:

if (emp is Person) { 
// Type check 
emp.firstName = 'Bob'; 
} 

//you can make the code shorter using as
(emp as Person).firstName = 'Bob';

Note: The code isn’t equivalent. If emp is null or not a Person, the first example (with is) does nothing; the second (with as) throws an exception.

Assignment operators

As you’ve already seen, you can assign values using the = operator. To assign only if the assigned-to variable is null, use the ??= operator.

// Assign value to a 
a = value; 

// Assign value to b if b is null; otherwise, b stays the same 
b ??= value; 

Compound assignment operators such as += combine an operation with an assignment.

=
–=
/=
%=
>>=
^=
+=
*=
~/=
<<=
&=
|=

The following example uses assignment and compound assignment operators: 

var a = 2; // Assign using = 
a *= 3; // Assign and multiply: a = a * 3
assert(a == 6);

Logical operators

You can invert or combine boolean expressions using the logical operators. 

!expr
inverts the following expression (changes false to true, and vice versa) 
||
logical OR
&&
logical AND

Here’s an example of using the logical operators: 

if (!done && (col == 0 || col == 3)) { 
// ...Do something... 
}

Bitwise and shift operators

You can manipulate the individual bits of numbers in Dart. Usually, you’d use these bitwise and shift operators with integers

&
AND
|
OR
^
XOR
~expr 
Unary bitwise complement (0s become 1s; 1s become 0s)
<<
Shift left
>>
Shift right

Here’s an example of using bitwise and shift operators:

final value = 0x22;
final bitmask = 0x0f;
assert((value & bitmask) == 0x02); // AND
assert((value & ~bitmask) == 0x20); // AND NOT
assert((value | bitmask) == 0x2f); // OR
assert((value ^ bitmask) == 0x2d); // XOR
assert((value << 4) == 0x220); // Shift
left assert((value >> 4) == 0x02); // Shift right

Conditional expressions

Dart has two operators that let you concisely evaluate expressions that might otherwise require if-else statements:

condition ? expr1 : expr2 

If condition is true, evaluates expr1 (and returns its value); otherwise, evaluates and returns the value of expr2.

expr1 ?? expr2 

If expr1 is non-null, returns its value; otherwise, evaluates and returns the value of expr2.

When you need to assign a value based on a boolean expression, consider using ?:.

var visibility = isPublic ? 'public' : 'private';

If the boolean expression tests for null, consider using ??.

String playerName(String name) => name ?? 'Guest';

The previous example could have been written at least two other ways, but not as succinctly:

// Slightly longer version uses ?: operator. 
String playerName(String name) => name != null ? name : 'Guest'; 

// Very long version uses if-else statement. 
String playerName(String name) { 
   if (name != null) { 
      return name; 
   } else { 
      return 'Guest'; 
   } 
}

Cascade notation (..)

Cascades (..) allow you to make a sequence of operations on the same object. In addition to function calls, you can also access fields on that same object. This often saves you the step of creating a temporary variable and allows you to write more fluid code.

Consider the following code:

querySelector('#confirm') // Get an object. 
..text = 'Confirm' // Use its members. 
..classes.add('important') 
..onClick.listen((e) => window.alert('Confirmed!'));

The first method call, querySelector(), returns a selector object. The code that follows the cascade notation operates on this selector object, ignoring any subsequent values that might be returned.

The previous example is equivalent to:

var button = querySelector('#confirm'); 
button.text = 'Confirm'; 
button.classes.add('important'); 
button.onClick.listen((e) => window.alert('Confirmed!')); 

You can also nest your cascades. For example:

final addressBook = (AddressBookBuilder() 
   ..name = 'jenny' 
   ..email = 'jenny@example.com' 
   ..phone = (PhoneNumberBuilder() 
      ..number = '415-555-0100' 
      ..label = 'home') 
   .build()) 
.build();

Be careful to construct your cascade on a function that returns an actual object. For example, the following code fails:

var sb = StringBuffer(); 
sb.write('foo') 
..write('bar'); // Error: method 'write' isn't defined for 'void'.

The sb.write() call returns void, and you can’t construct a cascade on void.

Note: Strictly speaking, the “double dot” notation for cascades is not an operator. It’s just part of the Dart syntax.

Other operators

You’ve seen most of the remaining operators in other examples:

()
Function application
Represents a function call
[]
List access
Refers to the value at the specified index in the list
.
Member access
Refers to a property of an expression; example: foo.bar selects property bar from expression foo
?.
Conditional member access
Like ., but the leftmost operand can be null; example: foo?.bar selects property bar from expression foo unless foo is null (in which case the value of foo?.bar is null)

Similar pages

Page structure
Terms

Dart

Functions

int

Methods

bool

double

String

List

Classes

Types

Numbers