Lógica booleana y el rigor del tipo bool en Dart
El tipo bool es el componente fundamental de la toma de decisiones en un programa. Representa un valor lógico que solo puede ser true o false. A diferencia de otros lenguajes como JavaScript o C, donde cualquier número o cadena de texto puede ser evaluada como “verdadera” o “falsa” (un concepto llamado truthy o falsy), Dart es estrictamente tipado. Esto significa que en Dart un 0 no es false, ni una cadena vacía "" es false. Si intentas usar un int o un String dentro de una estructura de control como un if, el compilador te detendrá inmediatamente.
Esta decisión de diseño de Dart busca eliminar la ambigüedad. En sistemas complejos, que un programador confunda accidentalmente un valor nulo o un cero con un valor booleano suele ser la semilla de bugs difíciles de rastrear. Al obligarte a ser explícito, Dart garantiza que la lógica de tu flujo de control sea siempre legible y predecible.
Para manejar la lógica, utilizamos operadores estándar: && (AND), que solo devuelve true si ambos operandos lo son; || (OR), que devuelve true si al menos uno lo es; y ! (NOT), que invierte el valor. Estos últimos emplean evaluación de cortocircuito: en un &&, si el primer operando es false, el segundo ni siquiera se evalúa porque el resultado ya está decidido. Un caso especial es el operador ^ (XOR), que devuelve true solo si los valores son distintos; es interesante porque en Dart funciona tanto para lógica booleana como para operaciones bitwise en int.
Para convertir texto a booleano, usamos bool.parse() [disponible desde Dart 1.0], que lanza una excepción si el string no es "true" o "false", o bool.tryParse(), que es más seguro y devuelve null si la conversión falla. Finalmente, con el sistema de null safety, podemos tener variables de tipo bool? (nullable), que representan tres estados: true, false o null.
void main() {
// Definición de estados de un usuario
final bool esAdmin = true;
final bool tieneSuscripcion = false;
final bool esInvitado = true;
// 1. Operadores Lógicos y Cortocircuito
// El operador && es exigente: ambos deben ser true.
final bool puedeAccederPrivado = esAdmin && tieneSuscripcion;
// El operador || es permisivo: basta con que uno sea true.
// Gracias al cortocircuito, si esAdmin fuera true, no evaluaría la suscripción.
final bool tieneAccesoBase = esAdmin || tieneSuscripcion;
// El operador ! (NOT) invierte el valor.
final bool noEsInvitado = !esInvitado;
// El operador ^ (XOR) devuelve true solo si los valores son diferentes.
// Útil para verificar si solo una de dos condiciones se cumple.
final bool soloUnoEsVerdad = esAdmin ^ tieneSuscripcion;
// 2. Parsing de Strings (Conversión segura)
const String entradaUsuario = "true";
const String entradaInvalida = "1"; // En Dart, "1" no es true
bool parseadoCorrecto = bool.parse(entradaUsuario);
bool? parseadoSeguro = bool.tryParse(entradaInvalida); // Retorna null
// 3. Null Safety con booleanos
// El tipo bool? permite la ausencia de valor (null)
bool? permisoDesconocido = null;
print('--- Resultados de Lógica ---');
print('Acceso Privado: $puedeAccederPrivado'); // false
print('Acceso Base: $tieneAccesoBase'); // true
print('No es invitado: $noEsInvitado'); // false
print('Solo uno es verdad: $soloUnoEsVerdad'); // true
print('Parseo seguro (invalido): $parseadoSeguro'); // null
print('\n--- Manejo de Nullables ---');
// No podemos hacer: if (permisoDesconocido) ... porque el tipo es bool?
// Debemos comparar explícitamente contra true o usar validación de nulidad.
if (permisoDesconocido == true) {
print('El permiso es explícitamente true');
} else {
print('El permiso es false o es null');
}
// El uso de ! (null assertion) solo si estás 100% seguro de que no es null
print('Valor parseado correcto: ${parseadoCorrecto.toString()}');
}
Análisis del código
En el ejemplo, observa cómo puedeAccederPrivado resulta en false porque, aunque esAdmin es true, la condición tieneSuscripcion es false, y el operador && requiere que ambas se cumplan.
Cuando evaluamos tieneAccesoBase, el motor de Dart aplica la evaluación de cortocircuito: si esAdmin hubiera sido false, Dart habría tenido que revisar tieneSuscripcion para decidir el resultado; pero como esAdmin es true y usamos ||, el proceso se detiene ahí por eficiencia.
En la sección de parsing, es vital notar la diferencia de comportamiento: bool.parse("1") causaría que tu aplicación colapsara con una excepción en runtime, mientras que bool.tryParse("1") nos devuelve un null elegante que podemos manejar.
Finalmente, la parte de null safety es crucial. Al definir permisoDesconocido como bool?, el compilador te impide usarlo directamente en un if. Esto te obliga a decidir qué hacer cuando el valor es null: ¿se trata como false o es un error? Al escribir if (permisoDesconocido == true), estás resolviendo la ambigüedad de forma segura, ya que la expresión solo será verdadera si el valor es exactamente true y no null.
El error frecuente
Un error común cuando se migra de JavaScript a Dart es intentar usar un objeto o un número directamente en una condición lógica:
// ERROR: Esto no compilará en Dart
int nivel = 1;
if (nivel) {
// Error: El tipo 'int' no puede ser asignado a la variable de tipo 'bool'
print('Nivel alto');
}
// ERROR: Intento de usar un booleano nullable sin verificar
bool? esPremium = null;
if (esPremium) {
// Error: El tipo 'bool?' no puede ser usado donde se requiere 'bool'
print('Bienvenido VIP');
}
Para solucionar el primer caso, debes ser explícito: if (nivel > 0). Para el segundo, debes usar if (esPremium == true) o el operador de coalescencia nula: if (esPremium ?? false).
N° 13