Condicionales
Cómo se consigue que un programa tome caminos distintos según los datos: el if, el if/else, los condicionales encadenados, el switch y los errores típicos de quien empieza.
Cuando el programa tiene que decidir
Hasta aquí, todo lo que se ha visto se ejecuta de arriba abajo, una línea detrás de otra, sin saltarse ninguna. A eso se le llama secuencia, y con secuencia sola no se puede escribir ningún programa útil, porque un programa tiene que reaccionar a los datos: si el alumno ha sacado un cinco o más, aprobado; si no, suspenso. Eso ya no es una lista fija de pasos, es una decisión.
La programación estructurada demostró que cualquier programa, por complicado que sea, se puede construir combinando solo tres formas de organizar las instrucciones. No hace falta nada más.
- Secuencia: las instrucciones se ejecutan una detrás de otra, en orden.
- Selección: se elige entre dos o más caminos según se cumpla o no una condición. Es lo que se ve en este subtema.
- Iteración o repetición: un grupo de instrucciones se repite mientras se cumpla una condición. Es el subtema siguiente.
A la selección se la llama también bifurcación, porque el camino del programa se abre en dos como una carretera que se separa. Y lo que decide por qué ramal se sigue es siempre lo mismo: una condición, es decir, una expresión que al calcularse da verdadero o falso. De ahí que los operadores relacionales y lógicos del subtema anterior sean el material del que están hechos los condicionales.
Todo condicional se apoya en una expresión booleana. Si esa expresión da verdadero se ejecuta un bloque y si da falso se ejecuta otro o ninguno, pero nunca los dos.
Para el examen
Las tres estructuras de la programación estructurada: secuencia, selección e iteración
Selección: los condicionales
Iteración: los bucles
El if y el if/else
La forma más simple es el if a secas, que se lee literalmente como «si se cumple esto, haz aquello». Si la condición es falsa, el bloque se salta entero y el programa continúa por debajo como si no existiera.
real nota = 6.5
if (nota >= 5) {
escribir("Tema superado")
}
escribir("Fin de la correccion")- Línea 3: entre paréntesis va la condición. Se calcula y da verdadero, porque 6.5 es mayor o igual que 5.
- Línea 4: como la condición ha sido verdadera, se ejecuta lo que hay dentro de las llaves y aparece «Tema superado».
- Línea 5: la llave cierra el bloque. Aquí acaba lo que depende de la condición.
- Línea 7: esta línea está fuera del if, así que se ejecuta siempre, valga lo que valga la nota. Es la confusión más habitual al leer código: lo que manda no es el orden en la página, es si está dentro o fuera de las llaves.
Cuando además hay que hacer algo en el caso contrario se añade un else, que se lee como «si no». Con un if/else siempre se ejecuta exactamente uno de los dos bloques: nunca los dos y nunca ninguno. El else no lleva condición propia, porque su condición es justo la contraria de la del if.
real nota = 3.2
if (nota >= 5) {
escribir("Tema superado")
temasSuperados++
} else {
escribir("Tema pendiente de repaso")
temasPendientes++
}Aquí la condición da falso, así que el programa se salta las dos líneas del primer bloque sin ejecutarlas y va directamente a las del else: escribe que el tema queda pendiente e incrementa el contador de pendientes. El contador de superados no se toca. Obsérvese que cada rama puede contener tantas instrucciones como haga falta, no solo una.
Con un if solo, si la condición es falsa no se hace nada. Con un if/else siempre se ejecuta una de las dos ramas, y solo una.
Para el examen
Con if/else: se ejecuta exactamente una de las dos ramas
Qué delimita el bloque: las llaves, no la sangría
Condicionales encadenados y anidados
Muchas decisiones no son de sí o no, sino de elegir entre varios casos. Para eso se encadenan condiciones poniendo un if nuevo detrás del else, lo que se escribe junto como else if y se conoce como escalera de condicionales. El programa va bajando peldaño a peldaño y se para en el primero que se cumple.
real nota = 7.4
if (nota >= 9) {
escribir("Dominado")
} else if (nota >= 7) {
escribir("Consolidado")
} else if (nota >= 5) {
escribir("Justo, conviene repasar")
} else {
escribir("Pendiente")
}- Se prueba la primera condición: 7.4 no llega a 9, así que es falsa y se pasa al siguiente peldaño.
- Se prueba la segunda: 7.4 sí es mayor o igual que 7, así que es verdadera. Se escribe «Consolidado».
- En cuanto una condición se cumple, TODO el resto de la escalera se salta. La tercera condición ni se llega a mirar, aunque 7.4 también sea mayor que 5.
- El else final no lleva condición: recoge todo lo que no ha encajado en ningún peldaño anterior. Es opcional, pero conviene ponerlo para que no haya casos sin tratar.
De ahí sale el error más típico de las escaleras: escribirlas en el orden equivocado. Si el ejemplo anterior empezara preguntando por nota >= 5, esa condición se cumpliría también para un nueve y para un ocho, y todas las notas aprobadas acabarían clasificadas como «Justo, conviene repasar». Las escaleras se ordenan siempre de la condición más restrictiva a la más general.
Cosa distinta es anidar, que es meter un if dentro de otro. Sirve cuando la segunda pregunta solo tiene sentido si la primera se ha cumplido: primero se comprueba que el alumno haya hecho el test y, solo dentro de ese caso, se mira qué nota sacó. Encadenar reparte casos excluyentes entre sí; anidar añade condiciones sucesivas sobre el mismo caso.
En una escalera de else if se ejecuta como mucho una rama: la primera cuya condición sea cierta. Por eso el orden de los peldaños cambia el resultado, y hay que ir de lo más restrictivo a lo más general.
Para el examen
Escalera de else if: se para en la primera condición cierta y descarta el resto
Cómo se ordena: de lo más restrictivo a lo más general
Anidar: es otra cosa: un if dentro de otro
El switch
Cuando la decisión consiste en comparar una misma variable con una lista de valores concretos, la escalera de else if queda repetitiva. Para eso está el switch, que evalúa una sola vez la variable y salta directamente al caso que coincide.
entero bloque = 3
switch (bloque) {
case 1:
escribir("Organizacion del Estado")
break
case 2:
escribir("Informatica basica")
break
case 3:
escribir("Desarrollo de sistemas")
break
default:
escribir("Bloque no reconocido")
}- Línea 3: entre paréntesis va la variable que se va a comparar, una sola vez. No una condición, sino el valor a examinar.
- Cada case indica un valor posible. El programa salta al case cuyo valor coincide, aquí el 3, e ignora los anteriores.
- El break cierra el caso y saca al programa del switch. Sin él, la ejecución continuaría hacia abajo por los case siguientes.
- El default recoge lo que no coincide con ningún case. Cumple el mismo papel que el else final de una escalera y también es opcional.
Ese break es la trampa clásica del switch. Si se olvida, el programa no se detiene al terminar el caso: sigue ejecutando el contenido de los casos siguientes hasta encontrar un break o llegar al final. Ese comportamiento se llama caída o fall-through, y a veces se usa a propósito para que varios valores compartan la misma respuesta, pero cuando es un descuido produce una salida desconcertante.
El switch tiene además una limitación importante frente a la escalera de if: solo compara igualdad con valores concretos y constantes. No se puede escribir un case para «mayor que 7», ni para un rango. En cuanto la decisión deja de ser una lista cerrada de valores, hay que volver al else if.
| Escalera de if / else if | switch | |
|---|---|---|
| Qué evalúa | Una condición distinta e independiente en cada rama | Una sola variable, comparada por igualdad con cada case |
| Admite rangos y comparaciones | Sí: mayor que, menor que, condiciones compuestas | No: solo valores concretos |
| Qué la cierra | Nada, cada rama es independiente | El break, y si falta la ejecución continúa hacia abajo |
| Caso por defecto | El else final | La rama default |
| Cuándo conviene | Condiciones variadas o por rangos | Muchos valores fijos de una misma variable |
Para el examen
Qué compara: una variable por igualdad con valores concretos; nada de rangos
Sin break: la ejecución cae al case siguiente (fall-through)
default: recoge lo que no encaja en ningún case
El operador condicional ternario
Hay un caso que se repite tanto que casi todos los lenguajes le han dado una forma abreviada: cuando lo único que se quiere es asignar un valor u otro a una variable según una condición. Escribirlo con un if/else de cuatro líneas funciona, pero existe un atajo que cabe en una.
// Con if/else
cadena estado
if (nota >= 5) {
estado = "Superado"
} else {
estado = "Pendiente"
}
// Exactamente lo mismo con el operador ternario
cadena estado = (nota >= 5) ? "Superado" : "Pendiente"La última línea se lee así: se evalúa la condición del paréntesis; si es verdadera, la expresión entera toma el valor que hay entre la interrogación y los dos puntos; si es falsa, toma el que hay después de los dos puntos. Ese valor resultante es el que se asigna a la variable.
Se le llama ternario porque es el único operador que trabaja con tres operandos: la condición, el valor para el caso verdadero y el valor para el caso falso. Todos los demás operadores del tema son unarios o binarios.
El ternario no añade capacidad ninguna: es una abreviatura de un if/else que asigna. Su interés en examen es que es el único operador de tres operandos.
Para el examen
Forma: condicion ? valorSiCierta : valorSiFalsa
Qué abrevia: un if/else que asigna
Su singularidad: es el único operador con tres operandos
Los errores típicos con condicionales
Los fallos de quien empieza con condicionales son siempre los mismos cuatro o cinco, y ninguno de ellos impide que el programa funcione: simplemente hace lo que no se le ha pedido, que es mucho peor que un error visible.
if (nota = 5) { ... } // 1. asigna en vez de comparar
if (nota >= 5); // 2. punto y coma: el if se queda vacio
{
escribir("Superado") // esto se ejecuta SIEMPRE
}
if (nota > 5 || 7) { ... } // 3. el 7 suelto no es una comparacion
if (media == 0.3) { ... } // 4. igualdad exacta entre reales
if (nombre == "Ana") { ... } // 5. en muchos lenguajes compara identidad,
// no el contenido del texto- El igual simple asigna y el doble compara. En lenguajes como C esto no da ni un aviso: modifica la variable y decide el camino con el valor recién metido.
- Un punto y coma justo detrás del paréntesis cierra el if con un cuerpo vacío. El bloque de llaves que viene detrás deja de depender de la condición y se ejecuta siempre.
- Cada lado de un operador lógico tiene que ser una condición completa. Lo correcto sería nota > 5 || nota > 7.
- Comparar reales con igualdad exacta falla por la precisión de la coma flotante: hay que comprobar que la diferencia sea menor que un margen.
- Para comparar el contenido de dos cadenas, muchos lenguajes exigen un método específico en vez del operador de igualdad.
Hay un sexto que no es un error de sintaxis sino de lógica: dejar casos sin cubrir. Si una escalera clasifica notas y ninguna rama contempla el valor exacto de corte, ese caso concreto se cae por el hueco. Repasar siempre qué pasa en los extremos, con el cero y con el valor límite, es lo que más errores evita.
Ninguno de estos fallos impide que el programa se ejecute. Todos producen programas que funcionan y dan un resultado equivocado, y por eso cuestan tanto de encontrar.
Para el examen
El más frecuente: usar = en vez de ==
Punto y coma tras el paréntesis: deja el if vacío y el bloque se ejecuta siempre
Comparar cadenas con ==: compara referencias, no contenido
Comparar reales: con igualdad exacta
Las llaves y el problema del else colgante
Muchos lenguajes permiten omitir las llaves cuando el cuerpo de un if tiene una sola instrucción. Es cómodo y es una fuente de errores conocida, porque lo que decide qué pertenece al if no es la sangría del texto sino la regla del lenguaje.
if (nota >= 5)
escribir("Superado")
temasSuperados++ // NO pertenece al if: se ejecuta siempre
// Con llaves no hay duda:
if (nota >= 5) {
escribir("Superado")
temasSuperados++
}Sin llaves, el if gobierna únicamente la instrucción inmediatamente siguiente. La segunda línea está sangrada igual, parece parte del bloque y no lo es: se ejecuta pase lo que pase con la nota. El compilador no ve la sangría, solo la sintaxis.
El caso extremo de esto es el else colgante o dangling else. Cuando hay dos if anidados sin llaves y un solo else, la ambigüedad es real: ese else puede leerse como perteneciente a cualquiera de los dos if. La regla que aplican los lenguajes es que el else se asocia siempre al if más cercano sin else, que a menudo no es el que el programador tenía en la cabeza.
if (haHechoElTest)
if (nota >= 5)
escribir("Superado")
else
escribir("Suspenso") // se asocia al SEGUNDO if, no al primero
// Es decir: si NO ha hecho el test, no se escribe nada.
// El else solo actua cuando ha hecho el test y ha sacado menos de 5.El else se empareja con el if más próximo que no tenga ya uno, independientemente de cómo esté sangrado el código. Poner siempre las llaves elimina el problema de raíz.
Para el examen
Sin llaves: el if gobierna solo la instrucción siguiente
Else colgante: se asocia al if más cercano sin else, no al que sugiere la sangría