Existen dos variantes de sintaxis en cascada: .. y ?..
Ejecutar múltiples asignaciones de propiedades y llamadas a métodos consecutivas sobre el mismo objeto, elimina las variables temporales y hace el código más fluido y coherente.
La sintaxis en cascada no es un operador, se trata de un azúcar sintáctico exclusivo de Dart.
1. Cascada normal ..
Se usa cuando se tiene la certeza de que el objeto nunca es null
Todas las operaciones con .. actúan sobre el objeto original del inicio, ignorando los valores devueltos por cada método intermedio.
Ejemplo oficial
import 'dart:ui';
void main() {
// Escritura en cascada
var paint = Paint()
..color = Colors.black
..strokeCap = StrokeCap.round
..strokeWidth = 5.0;
// Forma dividida equivalente (sin cascada, repetir nombre de variable)
var paint2 = Paint();
paint2.color = Colors.black;
paint2.strokeCap = StrokeCap.round;
paint2.strokeWidth = 5.0;
}Lenguaje del código: JavaScript (javascript)
Este ejemplo importa la librería dart:ui propia de Flutter, solo utilizable dentro de proyectos Flutter. Al ser una guía sobre Dart puro, solo hace falta comprender la lógica sintáctica mostrada arriba. El siguiente ejemplo usa una clase nativa propia de Dart: StringBuffer.
Clase para manipulación de cadenas: StringBuffer
void main() {
// Sintaxis en cascada
var sb = StringBuffer()
..write("Hello ")
..write("FoxDevelop.com ")
..writeln("Cascade");
print(sb.toString());
// Versión equivalente sin cascada
var sb2 = StringBuffer();
sb2.write("Hello ");
sb2.write("FoxDevelop.com ");
sb2.writeln("Cascade");
print(sb2.toString());
}Lenguaje del código: PHP (php)
Resultado de ejecución
D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
Hello FoxDevelop.com Cascade
Hello FoxDevelop.com CascadeLenguaje del código: CSS (css)
La sintaxis anterior se emplea cuando estás seguro de que objetos como paint, sb o sb2 jamás valen null: permite asignar valores rápidamente sin repetir el nombre del objeto. En cambio, si el objeto es null, se produce un error inmediato.
void main() {
var sb = null
..write("Hello ")
..write("FoxDevelop.com ")
..writeln("Cascade");
print(sb.toString());
}Lenguaje del código: JavaScript (javascript)

Para solucionar este inconveniente existe la segunda variante que se describe a continuación.
2. Cascada segura contra null ?..
Si el objeto vale null, toda la cadena de cascada no se ejecuta, evitando errores de puntero nulo. Solo el primer eslabón usa ?..; los siguientes llevan directamente ...
void main() {
var sb = null
?..write("Hello ")
..write("FoxDevelop.com ")
..writeln("Cascade");
print(sb.toString());
}Lenguaje del código: Dart (dart)
Fíjate bien en el signo de interrogación antes de ?..write(«Hello «)
Al compilar nuevamente, el programa se ejecuta sin fallos
D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
nullLenguaje del código: CSS (css)
No se genera ningún error
A continuación el ejemplo oficial: solo tienes que conocer la forma sintáctica.
// Empezar con ?.., luego solo usar ..
document.querySelector('#confirm')
?..textContent = 'Confirm'
..classList.add('important')
..onClick.listen((e) => window.alert('Confirmed!'))
..scrollIntoView();
// Forma dividida segura contra null equivalente
final button = document.querySelector('#confirm');
button?.textContent = 'Confirm';
button?.classList.add('important');
button?.onClick.listen((e) => window.alert('Confirmed!'));
button?.scrollIntoView();Lenguaje del código: JavaScript (javascript)
Cascadas anidadas
final addressBook = (AddressBookBuilder()
..name = 'jenny'
..email = 'jenny@example.com'
// Cascada independiente para el objeto interno PhoneNumberBuilder
..phone = (PhoneNumberBuilder()
..number = '415-555-0100'
..label = 'home')
.build())
.build();Lenguaje del código: PHP (php)
El atributo phone es un objeto instanciado mediante PhoneNumberBuilder() al que se le asignan valores.
Observaciones importantes
La sintaxis en cascada solo puede aplicarse sobre instancias de objeto; si se coloca después de un método que retorna void, saldrá un error de compilación.
var sb = StringBuffer();
sb.write('foo') // write retorna void
..write('bar'); // Error: el tipo void no posee el método writeLenguaje del código: Dart (dart)
Aquí primero creamos una instancia de StringBuffer llamada sb
Pero la instrucción finaliza con punto y coma antes de llamar al método write sobre sb; como write devuelve void, no se puede encadenar otro ..write a continuación, a menos que el método write retorne una instancia de objeto.
Forma correcta de escribirlo
var sb = StringBuffer()
..write('foo')
..write('bar');Lenguaje del código: Dart (dart)
Resumen
..vuelve siempre al objeto raíz original en cada operación, ignorando los valores devueltos por los métodos. Equivale al encadenamiento de métodos presente en otros lenguajes como JavaScript.?..es la cascada segura contra null para evitar errores cuando el objeto es null. Solo se usa al principio de la cadena: si la primera operación se ejecuta, el objeto no es null, por lo que los eslabones siguientes no requieren ?..- Se admiten cascadas anidadas
- No se puede colocar una cascada después de un método con tipo de retorno
void ..no es un operador, sino un azúcar sintáctico propio de Dart
¿Qué es el azúcar sintáctico?
El azúcar sintáctico es una abreviatura ligera ofrecida por un lenguaje de programación para una misma lógica subyacente durante el análisis sintáctico; no añade capacidades nuevas al lenguaje. El compilador o intérprete convierte automáticamente esta sintaxis abreviada al código estándar equivalente antes de generar el código intermedio.