Skip to main content
The = operator performs simple assignment, evaluating the expression on the right-hand side (RHS) and assigning the resulting object reference to the l-value on the left-hand side (LHS). Depending on the target l-value, this operation either updates a variable’s storage or invokes a specific mutator method.

Syntax

l_value = expression;

Valid L-Values

An l-value is an expression that identifies a specific storage location or mutator. In Dart, valid l-values are classified as:
  1. Variables: Identifiers for direct storage, including local variables, parameters, top-level variables, and static variables (fields).
  2. Properties: Accessors that resolve to setter methods. This includes instance variables (implicit setters), explicit instance setters, and static setters.
  3. Subscript Expressions: Elements accessed via the subscript operator [].

Operational Semantics

The execution of an assignment proceeds as follows:
  1. RHS Evaluation: The expression on the right is evaluated to produce a value (an object reference).
  2. Assignment Mechanism:
    • Variable Update: If the LHS is a variable, the operator updates the variable to hold the reference to the new object.
    • Setter Invocation: If the LHS is a property, the operator invokes the corresponding setter method (implicit or explicit), passing the RHS value as the argument.
    • Subscript Operator Invocation: If the LHS is a subscript expression (e.g., list[i]), the operator invokes the operator []= method on the target object.
  3. Return Value: The assignment expression resolves to the value of the RHS. This allows the assignment to be used as an expression within larger statements.

Type Safety Rules

Dart enforces static type checking on assignments. For an assignment to be valid, the static type of the RHS expression must be a subtype of the static type of the LHS. Since the introduction of sound null safety, implicit downcasts are prohibited for non-dynamic types. A supertype cannot be assigned to a subtype without an explicit cast.
num genericNumber = 10;
int specificInteger = 5;

// Valid: 'int' is a subtype of 'num' (Upcast)
genericNumber = specificInteger;

// Compile-time Error: 'num' is not assignable to 'int' (Implicit downcast prohibited)
// specificInteger = genericNumber;

// Valid: Explicit cast allows the assignment (Runtime check required)
specificInteger = genericNumber as int;

Associativity

The = operator is right-associative. When multiple assignments are chained, they are evaluated from right to left.
int a, b, c;

// 1. 'c = 5' is evaluated first. Returns 5.
// 2. 'b = 5' is evaluated next. Returns 5.
// 3. 'a = 5' is evaluated last.
a = b = c = 5;

Code Representation

Variable Assignment Updates the reference held by x.
int x = 10;
x = 20; // x now references the integer object 20
Property Assignment (Setter) Invokes the implicit or explicit setter on the object or class.
class Container {
  static int _staticVal = 0;
  int _val = 0;
  
  // Explicit instance setter
  set val(int v) => _val = v;
  
  // Explicit static setter
  static set staticVal(int v) => _staticVal = v;
}

var c = Container();
c.val = 42;           // Invokes the instance 'val' setter with argument 42
Container.staticVal = 10; // Invokes the static 'staticVal' setter with argument 10
Subscript Assignment Invokes the operator []= method on the collection instance.
var list = [1, 2, 3];
list[0] = 99; // Invokes the []= operator with index 0 and value 99

Immutability Constraints

The = operator cannot be used to reassign identifiers marked as final or const once they have been initialized.
final int fixed = 100;
// fixed = 200; // Compile-time Error: The final variable 'fixed' can only be set once.
Master Dart with Deep Grasping Methodology!Learn More