Dart es un lenguaje de programación de propósito general, diseñado para ser eficiente, rápido y, sobre todo, seguro. Nació en 2011 [disponible desde 2011] como la respuesta de Google a la complejidad de JavaScript en aplicaciones web de gran escala. Mientras que JavaScript fue concebido para añadir pequeñas interacciones a páginas web, Dart se construyó con la ambición de ser un lenguaje robusto para aplicaciones completas, con una estructura que facilita el trabajo de equipos grandes y evita los errores típicos de tipos dinámicos.
Su diseño se basa en la productividad y la predictibilidad. Para lograrlo, Dart ha evolucionado significativamente: pasó de tener un sistema de tipos opcional a implementar un sistema de Sound Null Safety [disponible desde Dart 2.12], lo que significa que el compilador puede garantizar matemáticamente que una variable que no permite valores nulos nunca será null en tiempo de ejecución. Este rigor es lo que permite que el motor de Dart pueda optimizar el código de forma tan agresiva mediante compilación AOT (Ahead-of-Time) para móviles y JIT (Just-in-Time) para desarrollo rápido.
¿Cuándo deberías usarlo? El escenario ideal hoy es el desarrollo multiplataforma con Flutter, donde necesitas un mismo código para iOS, Android y Web, o cuando construyes servicios de backend que requieren alta concurrencia y un modelo de tipos sólido. Si intentas usar Dart ignorando su sistema de tipos o forzando la nulidad cuando no es necesario, estarás luchando contra la herramienta en lugar de aprovechar su capacidad para prevenir errores antes de que lleguen al usuario.
void main() {
// Una variable estándar: no puede ser nula nunca.
// El compilador garantiza que 'nombre' siempre tendrá un valor.
String nombre = 'Lars';
print('Desarrollador: $nombre');
// Una variable "nullable": el signo '?' le dice a Dart que puede ser nula.
// Esto es una evolución clave para evitar errores de ejecución.
String? apellido;
print('Apellido actual: $apellido'); // Imprimirá 'null'
// Asignamos un valor
apellido = 'Bak';
print('Apellido actualizado: $apellido');
// El sistema de tipos nos obliga a verificar si es nulo antes de usarlo
// como si fuera un String normal.
int longitud = apellido?.length ?? 0;
print('La longitud del apellido es: $longitud');
}
En el ejemplo anterior, fíjate en la diferencia fundamental entre String y String?. Cuando declaras String nombre, le estás haciendo una promesa al compilador: “esta variable siempre contendrá un texto”. Si intentaras asignarle null, el código ni siquiera compilaría. Esto es lo que hace que Dart sea “seguro”.
En cambio, al usar String? apellido, estamos siendo honestos con el sistema: estamos admitiendo que, en algún momento, ese valor podría no estar presente. Cuando intentamos obtener la longitud con apellido?.length, estamos usando una operación segura que devuelve null si el apellido no existe, en lugar de romper la aplicación. El operador ?? (operador de coalescencia nula) es la forma en que decimos: “si lo de la izquierda es nulo, usa el valor de la derecha (en este caso, 0)”. Esta combinación de tipos estrictos y manejo explícito de nulos es el núcleo de la estabilidad que Google buscaba al alejarse del modelo errático de JavaScript.
El error frecuente
Un error común cuando se empieza con el sistema de null safety es intentar forzar la salida del sistema de tipos usando el operador de aserción de nulos !.
void errorEjemplo() {
String? nombreNulo;
// Esto fallará en tiempo de ejecución porque estamos prometiendo
// que 'nombreNulo' no es nulo, pero sabemos que sí lo es.
print(nombreNulo!.length);
}
Al usar !, le dices al compilador: “confía en mí, yo sé que esto no es nulo”. Si te equivocas y el valor es efectivamente null, la aplicación lanzará una excepción y se detendrá. Úsalo solo cuando estés absolutamente seguro de la lógica de tu flujo, no como un parche para evitar errores de compilación.
N° 1