Skip to main content
The dot operator (.) is a primary syntactic mechanism used for member access, method invocation, and namespace resolution. It establishes a relationship between a left-hand operand (the receiver or scope) and a right-hand operand (the identifier) to retrieve values or invoke behavior.

Syntax

receiver.identifier

Instance Member Access and Resolution

When the left-hand operand is an expression evaluating to an object instance, the dot operator resolves the identifier based on the static type of the receiver.
  1. Interface Resolution: The compiler first attempts to resolve the identifier as a member (field, getter, setter, or method) defined in the interface of the receiver’s static type.
  2. Extension Resolution: If the member is not found in the type definition, the compiler checks for applicable extension members (methods, getters, setters, or operators) available in the current scope that match the receiver’s static type.
  3. Dynamic Dispatch: If the static type is dynamic, member resolution is deferred until runtime.
class Box {
  int value = 10;
}

extension BoxExt on Box {
  // Extension getter
  int get doubled => value * 2;
}

void main() {
  Box b = Box();
  
  // Resolves to the instance field 'value' defined on Box
  print(b.value); 
  
  // Resolves to the extension getter 'doubled' defined in BoxExt
  print(b.doubled);
}

Static Member and Constructor Access

When the left-hand operand is a type identifier (referencing a class, mixin, or enum directly), the dot operator accesses static members or named constructors associated with that type. This differs from a type literal (which evaluates to a Type object) and allows access to the namespace of the type definition itself.
// Accessing a static property via the class identifier 'double'
var max = double.maxFinite;

// Invoking a static method via the class identifier 'int'
var parsed = int.parse('100');

// Invoking a named constructor via the class identifier 'DateTime'
var now = DateTime.now();

Library Prefix Access

When a library is imported with a prefix using the as keyword, the dot operator resolves symbols within that library’s namespace. In this context, the left-hand operand is the library prefix, and the right-hand operand is a top-level definition (such as a class, variable, or function).
import 'dart:math' as math;

// 'math' is the prefix; 'pi' is the top-level variable
var circleArea = math.pi * 10 * 10;

Nullability and Object Members

Dart’s sound null safety restricts the use of the standard dot operator on nullable types.
  1. Members of Object: The operator is permitted on a nullable receiver only if the identifier corresponds to a member defined on Object (toString, hashCode, runtimeType).
  2. Other Members: Accessing any other member on a nullable receiver results in a compile-time error, requiring the use of the null-aware operator (?.) or null assertion (!).
String? nullableText = null;

// Allowed: 'hashCode' is defined on Object
int code = nullableText.hashCode;

// Compile-time Error: 'length' is not defined on Object
// var len = nullableText.length;

Operator Precedence and Associativity

The dot operator belongs to the highest precedence tier in Dart (postfix operators). It shares this precedence level with (), [], ?[], ++, and --. Operators in this tier are left-associative. When multiple operators of this tier appear in sequence, they are evaluated from left to right.
var list = ['a', 'b', 'c'];

// Evaluation order:
// 1. list[0] -> returns String 'a'
// 2. 'a'.toUpperCase() -> returns String 'A'
var result = list[0].toUpperCase();
Master Dart with Deep Grasping Methodology!Learn More