En informática , los condicionales (es decir, declaraciones condicionales , expresiones condicionales y construcciones condicionales ) son construcciones del lenguaje de programación que realizan diferentes cálculos o acciones o devuelven diferentes valores dependiendo del valor de una expresión booleana , llamada condición .
Los condicionales se implementan normalmente mediante la ejecución selectiva de instrucciones. Aunque el envío dinámico no suele clasificarse como una construcción condicional, es otra forma de seleccionar entre alternativas en tiempo de ejecución .
Las sentencias condicionales son construcciones imperativas que se ejecutan para obtener efectos secundarios, mientras que las expresiones condicionales devuelven valores. Muchos lenguajes de programación (como C) tienen sentencias condicionales y expresiones condicionales distintas. Aunque en la programación funcional pura , las expresiones condicionales no tienen efectos secundarios , muchos lenguajes con expresiones condicionales (como Lisp) admiten efectos secundarios condicionales.
La construcción if–then
or se utiliza en muchos lenguajes de programación. Aunque la sintaxis varía de un lenguaje a otro, la estructura básica (en forma de pseudocódigo ) es la siguiente:if–then–else
Si (condición booleana) Entonces (consiguiente)Demás (alternativa)Fin si
Por ejemplo:
Si stock=0 Entonces mensaje=pedir nuevo stockDemás mensaje=hay stockFin si
En el código de ejemplo anterior, la parte representada por (condición booleana) constituye una expresión condicional , que tiene un valor intrínseco (por ejemplo, puede sustituirse por cualquiera de los valores True
o False
) pero que no tiene significado intrínseco. Por el contrario, la combinación de esta expresión, el If
y Then
que la rodea y el consecuente que le sigue después constituyen una declaración condicional , que tiene un significado intrínseco (por ejemplo, expresa una regla lógica coherente) pero no tiene valor intrínseco.
Cuando un intérprete encuentra un If
, espera una condición booleana (por ejemplo, x > 0
, que significa "la variable x contiene un número mayor que cero") y evalúa esa condición. Si la condición es true
, se ejecutan las instrucciones que siguen al then
. De lo contrario, la ejecución continúa en la siguiente rama (ya sea en el else
bloque (que suele ser opcional) o, si no hay else
rama, después del end If
).
Después de ejecutar cualquiera de las ramas, el control vuelve al punto después de end If
.
En los primeros lenguajes de programación, especialmente algunos dialectos de BASIC en los ordenadores domésticos de los años 1980 , una if–then
sentencia sólo podía contener GOTO
sentencias (equivalentes a una instrucción de bifurcación ). Esto dio lugar a un estilo de programación difícil de leer conocido como programación espagueti , con programas en este estilo llamados código espagueti . Como resultado, la programación estructurada , que permite poner sentencias (prácticamente) arbitrarias en bloques de sentencias dentro de una if
sentencia, ganó popularidad, hasta convertirse en la norma incluso en la mayoría de los círculos de programación BASIC. Dichos mecanismos y principios se basaban en la antigua pero más avanzada familia de lenguajes ALGOL , y los lenguajes similares a ALGOL como Pascal y Modula-2 influyeron en las variantes modernas de BASIC durante muchos años. Si bien es posible, utilizando sólo GOTO
sentencias en if–then
sentencias, escribir programas que no sean código espagueti y que estén tan bien estructurados y sean tan legibles como los programas escritos en un lenguaje de programación estructurado, la programación estructurada lo hace más fácil y lo refuerza. Las declaraciones estructuradas if–then–else
como el ejemplo anterior son uno de los elementos clave de la programación estructurada y están presentes en los lenguajes de programación de alto nivel más populares, como C , Java , JavaScript y Visual Basic .
La else
palabra clave está diseñada para apuntar a una if–then
declaración específica que la precede, pero en el caso de las declaraciones anidadas if–then
, los lenguajes de programación clásicos como ALGOL 60 tenían dificultades para definir a qué declaración específica apuntar. Sin límites claros para cada declaración, una else
palabra clave podría apuntar a cualquier if–then
declaración anterior en el anidamiento, tal como se analiza.
Si a entonces si b entonces s de lo contrario s2
se puede analizar como
Si a entonces ( si b entonces s) de lo contrario s2
o
Si a entonces ( si b entonces s de lo contrario s2)
Dependiendo de si el else
está asociado con el primero if
o el segundo if
. Esto se conoce como el problema del else colgante y se resuelve de varias maneras, según el lenguaje (comúnmente a través de la end if
declaración o {...}
corchetes).
Al utilizar else if
, es posible combinar varias condiciones. Solo se ejecutarán las instrucciones que siguen a la primera condición que se considere verdadera. Se omitirán todas las demás instrucciones.
si condición entonces -- declaraciones elseif condición entonces -- más declaraciones elseif condición entonces -- más declaraciones;...else - otras declaraciones; fin si ;
Por ejemplo, para una tienda que ofrece hasta un 30% de descuento en un artículo:
Si el descuento < 11% entonces imprimir (tienes que pagar $30)De lo contrario, si el descuento es <21% , entonces imprimir (tienes que pagar $20)De lo contrario, si el descuento es <31% , entonces imprimir (tienes que pagar $10)fin si ;
En el ejemplo anterior, si el descuento es del 10 %, la primera declaración if se evaluará como verdadera y se imprimirá "tienes que pagar $30". Se omitirán todas las demás declaraciones que se encuentren debajo de esa primera declaración if.
La elseif
declaración, en el lenguaje Ada por ejemplo, es simplemente azúcar sintáctica para else
seguido de if
. En Ada, la diferencia es que solo end if
se necesita uno, si se usa elseif
en lugar de else
seguido de if
. PHP usa la elseif
palabra clave [1] tanto para sus sintaxis de llaves como de dos puntos. Perl proporciona la palabra clave elsif
para evitar la gran cantidad de llaves que serían requeridas por múltiples declaraciones if
y else
. Python usa la palabra clave especial elif
porque la estructura se denota por sangría en lugar de llaves, por lo que un uso repetido de else
y if
requeriría una sangría aumentada después de cada condición. Algunas implementaciones de BASIC , como Visual Basic , [2] usan ElseIf
too. De manera similar, los shells UNIX anteriores (posteriormente reunidos en la sintaxis de shell POSIX [3] ) también usan elif, pero dando la opción de delimitar con espacios, saltos de línea o ambos.
Sin embargo, en muchos lenguajes que descienden más directamente de Algol, como Simula , Pascal , BCPL y C , esta sintaxis especial para la else if
construcción no está presente, ni tampoco está presente en los muchos derivados sintácticos de C, como Java , ECMAScript , etc. Esto funciona porque en estos lenguajes, cualquier declaración individual (en este caso ...) puede seguir a un condicional sin estar encerrada en un bloque.if cond
Esta opción de diseño tiene un pequeño "costo". Cada else if
rama añade efectivamente un nivel de anidación adicional. Esto complica el trabajo del compilador (o de las personas que escriben el compilador), porque el compilador debe analizar e implementar else if
cadenas arbitrariamente largas de forma recursiva.
Si todos los términos de la secuencia de condicionales están probando el valor de una sola expresión (por ejemplo, if x=0
... else if x=1
... else if x=2
...), una alternativa es la sentencia switch , también llamada sentencia case o sentencia select. Por el contrario, en lenguajes que no tienen sentencia switch, estas pueden ser producidas por una secuencia de else if
sentencias.
Muchos lenguajes admiten expresiones if , que son similares a las instrucciones if, pero devuelven un valor como resultado. Por lo tanto, son expresiones verdaderas (que se evalúan como un valor), no instrucciones (que pueden no estar permitidas en el contexto de un valor).
ALGOL 60 y algunos otros miembros de la familia ALGOL permiten if–then–else
como expresión:
mivariable := si x > 20 entonces 1 sino 2
En los dialectos de Lisp ( Scheme , Racket y Common Lisp ), el primero de los cuales se inspiró en gran medida en ALGOL:
;; Esquema ( define myvariable ( if ( > x 12 ) 1 2 )) ; Asigna 'myvariable' a 1 o 2, dependiendo del valor de 'x'
;; Common Lisp ( let (( x 10 )) ( setq myvariable ( if ( > x 12 ) 2 4 ))) ; Asigna 'myvariable' a 2
En Haskell 98, solo hay una expresión if , no hay ninguna declaración if y la else
parte es obligatoria, ya que cada expresión debe tener algún valor. [4] La lógica que se expresaría con condicionales en otros lenguajes generalmente se expresa con coincidencia de patrones en funciones recursivas.
Como Haskell es perezoso , es posible escribir estructuras de control, como if , como expresiones ordinarias; la evaluación perezosa significa que una función if puede evaluar solo la condición y la rama apropiada (donde un lenguaje estricto evaluaría las tres). Se puede escribir de esta manera: [5]
si' :: Bool -> a -> a -> a si' Verdadero x _ = x si' Falso _ y = y
Los lenguajes C y similares tienen un operador ternario especial ( ?: ) para expresiones condicionales con una función que puede describirse mediante una plantilla como esta:
condition ? evaluated-when-true : evaluated-when-false
Esto significa que se puede incorporar en expresiones, a diferencia de las declaraciones if, en lenguajes tipo C:
my_variable = x > 10 ? "foo" : "bar" ; // En lenguajes tipo C
que puede compararse con las expresiones if–then–else de la familia Algol (en contraste con una declaración ) (y similares en Ruby y Scala, entre otros).
Para lograr lo mismo usando una declaración if, esto tomaría más de una línea de código (bajo las convenciones de diseño típicas) y requeriría mencionar "my_variable" dos veces:
si ( x > 10 ) mi_variable = "foo" ; de lo contrario mi_variable = "bar" ;
Algunos argumentan que la declaración explícita if/then es más fácil de leer y que puede compilarse en un código más eficiente que el operador ternario, [6] mientras que otros argumentan que las expresiones concisas son más fáciles de leer que las declaraciones distribuidas en varias líneas que contienen repeticiones.
x = TextWindow . ReadNumber () If ( x > 10 ) Then TextWindow . WriteLine ( "Mi variable se llama 'foo'." ) Else TextWindow . WriteLine ( "Mi variable se llama 'bar'." ) EndIf
En primer lugar, cuando el usuario ejecuta el programa, aparece un cursor esperando a que el lector escriba un número. Si ese número es mayor que 10, se muestra en la pantalla el texto "Mi variable se llama 'foo'". Si el número es menor que 10, se imprime en la pantalla el mensaje "Mi variable se llama 'bar'".
En Visual Basic y otros lenguajes, IIf
se proporciona una función llamada, que se puede utilizar como expresión condicional. Sin embargo, no se comporta como una expresión condicional verdadera, porque tanto la rama verdadera como la falsa siempre se evalúan; simplemente, el resultado de una de ellas se descarta, mientras que el resultado de la otra lo devuelve la función IIf.
En Tcl if
no es una palabra clave sino una función (en Tcl se la conoce como comando o proc
). Por ejemplo
si { $x > 10 } { pone "¡Foo!" }
invoca una función llamada if
y pasa 2 argumentos: el primero es la condición y el segundo es la rama verdadera. Ambos argumentos se pasan como cadenas (en Tcl, todo lo que está entre llaves es una cadena).
En el ejemplo anterior, la condición no se evalúa antes de llamar a la función. En cambio, la implementación de la if
función recibe la condición como un valor de cadena y es responsable de evaluar esta cadena como una expresión en el ámbito de los llamadores. [7]
Este comportamiento es posible mediante el uso de los comandos uplevel
y expr
:
Debido a que if
en realidad es una función, también devuelve un valor:
En Rust , if
siempre es una expresión. Se evalúa como el valor de la rama que se ejecuta, o como el tipo de unidad ()
si no se ejecuta ninguna rama. Si una rama no proporciona un valor de retorno, se evalúa como ()
de forma predeterminada. Para garantizar if
que se conozca el tipo de la expresión en el momento de la compilación, cada rama debe evaluarse como un valor del mismo tipo. Por este motivo, una else
rama es efectivamente obligatoria a menos que las otras ramas evalúen como ()
, porque una if
sin una else
siempre puede evaluarse como ()
de forma predeterminada. [10]
// Asigna a my_variable algún valor, dependiendo del valor de x let my_variable = if x > 20 { 1 } else { 2 }; // Esta variante no se compilará porque 1 y () tienen tipos diferentes let my_variable = if x > 20 { 1 }; // Los valores se pueden omitir cuando no sean necesarios si x > 20 { println! ( "x es mayor que 20" ); }
El lenguaje de comandos protegidos (GCL) de Edsger Dijkstra admite la ejecución condicional como una lista de comandos que consta de una protección con valor booleano (que corresponde a una condición ) y su instrucción correspondiente. En GCL, se evalúa exactamente una de las instrucciones cuya protección es verdadera, pero cuál es arbitraria. En este código
si G0 → S0 □ G1 → S1... □ Gn → Snen fin
Las G i son las protecciones y las S i son las instrucciones. Si ninguna de las protecciones es verdadera, el comportamiento del programa no está definido.
GCL está pensado principalmente para razonar sobre programas, pero se han implementado notaciones similares en Concurrent Pascal y Occam .
Hasta Fortran 77 , el lenguaje Fortran tenía una declaración aritmética if que salta a una de tres etiquetas dependiendo de si su argumento e es e < 0, e = 0, e > 0. Esta fue la primera declaración condicional en Fortran. [11]
SI ( e ) etiqueta1 , etiqueta2 , etiqueta3
Donde e es cualquier expresión numérica (no necesariamente un número entero).
Esto es equivalente a esta secuencia, donde e se evalúa solo una vez.
SI ( e . LT . 0 ) IR A etiqueta1 SI ( e . EQ . 0 ) IR A etiqueta2 SI ( e . GT . 0 ) IR A etiqueta3
La aritmética if es una declaración de control no estructurada y no se utiliza en programación estructurada .
En la práctica se ha observado que la mayoría de IF
las declaraciones aritméticas hacen referencia a la siguiente declaración con una o dos de las etiquetas.
Esta fue la única declaración de control condicional en la implementación original de Fortran en la computadora IBM 704. En esa computadora, el código de operación de prueba y bifurcación tenía tres direcciones para esos tres estados. Otras computadoras tendrían registros de "indicadores" como positivo, cero, negativo, par, desbordamiento, acarreo, asociados con las últimas operaciones aritméticas y usarían instrucciones como 'Bifurcar si acumulador negativo' y luego 'Bifurcar si acumulador cero' o similares. Tenga en cuenta que la expresión se evalúa solo una vez y, en casos como la aritmética de números enteros donde puede ocurrir un desbordamiento, también se considerarían los indicadores de desbordamiento o acarreo.
A diferencia de otros lenguajes, en Smalltalk la declaración condicional no es una construcción del lenguaje , sino que se define en la clase Boolean
como un método abstracto que toma dos parámetros, ambos cierres . Boolean
tiene dos subclases, True
y False
, que definen el método, True
ejecutando solo el primer cierre, False
ejecutando solo el segundo cierre. [12]
var = condición ifTrue: [ 'foo' ] ifFalse: [ 'bar' ]
JavaScript utiliza declaraciones if-else similares a las de los lenguajes C. Se acepta un valor booleano entre paréntesis entre la palabra clave reservada if y una llave izquierda.
if ( Math . random () < 0.5 ) { console . log ( "¡Obtuviste cara!" ); } else { console . log ( "¡Obtuviste cruz!" ); }
El ejemplo anterior toma la condición de Math.random() < 0.5
que se genera true
si un valor flotante aleatorio entre 0 y 1 es mayor que 0,5. La instrucción la utiliza para elegir aleatoriamente entre generar You got Heads!
o enviar You got Tails!
a la consola. Las instrucciones else y else-if también se pueden encadenar después de la llave de la instrucción que la precede tantas veces como sea necesario, como se muestra a continuación:
var x = Math . random (); if ( x < 1 / 3 ) { console . log ( "¡Una persona ganó!" ); } else if ( x < 2 / 3 ) { console . log ( "¡Dos personas ganaron!" ); } else { console . log ( "¡Es un empate entre tres!" ); }
En el cálculo lambda , el concepto de una condición if-then-else se puede expresar utilizando las siguientes expresiones:
verdadero = λx. λy. xfalso = λx. λy. ysiEntoncesDemás = (λc. λx. λy. (cxy))
nota : si a ifThenElse se le pasan dos funciones como condicionales izquierdo y derecho, es necesario pasar también una tupla vacía () al resultado de ifThenElse para poder llamar realmente a la función elegida; de lo contrario, ifThenElse simplemente devolverá el objeto de función sin ser llamado.
En un sistema donde se pueden usar números sin definición (como Lisp, matemáticas tradicionales en papel, etc.), lo anterior se puede expresar como un único cierre a continuación:
(( λverdadero. λfalso. λsiEntoncesDemás. ( siEntoncesDemás verdadero 2 3 ) )( λx. λy. x )( λx. λy. y )( λc. λl. λr. c l r ))
Aquí, verdadero, falso y ifThenElse están vinculados a sus respectivas definiciones, que se pasan a su ámbito al final de su bloque.
Una analogía funcional de JavaScript (usando solo funciones de una sola variable para mayor rigor) es la siguiente:
var computationResult = (( _true => _false => _ifThenElse => _ifThenElse ( _true )( 2 )( 3 ) )( x => y => x )( x => y => y )( c => x => y => c ( x )( y )));
El código anterior con funciones multivariables se ve así:
var computationResult = (( _true , _false , _ifThenElse ) => _ifThenElse ( _true , 2 , 3 ) )(( x , y ) => x , ( x , y ) => y , ( c , x , y ) => c ( x , y ));
A continuación se muestra otra versión del ejemplo anterior sin un sistema donde se asumen números.
El primer ejemplo muestra cómo se toma la primera rama, mientras que el segundo ejemplo muestra cómo se toma la segunda rama.
(( λverdadero. λfalso. λsiEntoncesDemás. ( siEntoncesDemás verdadero ( λPrimeraRama. PrimeraRama ) ( λSegundaRama. SegundaRama )) )( λx. λy. x )( λx. λy. y )( λc. λl. λr. c l r )) (( λverdadero. λfalso. λsiEntoncesDemás. ( siEntoncesDemás falso ( λPrimeraRama. PrimeraRama ) ( λSegundaRama. SegundaRama )) )( λx. λy. x )( λx. λy. y )( λc. λl. λr. c l r ))
Smalltalk utiliza una idea similar para sus representaciones verdaderas y falsas, donde Verdadero y Falso son objetos singleton que responden a los mensajes ifTrue/ifFalse de manera diferente.
Haskell solía usar este modelo exacto para su tipo booleano, pero al momento de escribir esto, la mayoría de los programas Haskell usan la construcción sintáctica "si a entonces b sino c" que, a diferencia de ifThenElse, no se compone a menos que esté envuelta en otra función o se vuelva a implementar como se muestra en la sección Haskell de esta página.
Las sentencias switch (en algunos lenguajes, sentencias case o ramas multidireccionales) comparan un valor dado con constantes especificadas y toman acción de acuerdo con la primera constante que coincida. Generalmente hay una disposición para que se tome una acción predeterminada ('else', 'otherwise') si no se logra ninguna coincidencia. Las sentencias switch pueden permitir optimizaciones del compilador , como tablas de búsqueda . En lenguajes dinámicos, los casos pueden no limitarse a expresiones constantes, y pueden extenderse a la coincidencia de patrones , como en el ejemplo de script de shell a la derecha, donde '*)' implementa el caso predeterminado como una expresión regular que coincide con cualquier cadena.
La comparación de patrones puede considerarse una alternativa a las instrucciones if-then-else y case . Está disponible en muchos lenguajes de programación con funciones de programación funcional, como Wolfram Language , ML y muchos otros. A continuación, se muestra un ejemplo simple escrito en el lenguaje OCaml :
combina la fruta con | "manzana" -> cocinar pastel | "coco" -> cocinar dango_mochi | "banana" -> mezclar ;;
El poder de la comparación de patrones es la capacidad de hacer coincidir de forma concisa no solo acciones sino también valores con patrones de datos. A continuación se muestra un ejemplo escrito en Haskell que ilustra ambas características:
mapa _ [] = [] mapa f ( h : t ) = f h : mapa f t
Este código define una función map , que aplica el primer argumento (una función) a cada uno de los elementos del segundo argumento (una lista) y devuelve la lista resultante. Las dos líneas son las dos definiciones de la función para los dos tipos de argumentos posibles en este caso: uno en el que la lista está vacía (solo devuelve una lista vacía) y el otro caso en el que la lista no está vacía.
En sentido estricto, la comparación de patrones no siempre es una construcción de elección, porque en Haskell es posible escribir solo una alternativa, que siempre se garantiza que coincidirá; en esta situación, no se utiliza como una construcción de elección, sino simplemente como una forma de vincular nombres a valores. Sin embargo, se utiliza con frecuencia como una construcción de elección en los lenguajes en los que está disponible.
En los lenguajes de programación que tienen matrices asociativas o estructuras de datos comparables, como Python , Perl , PHP o Objective-C , es idiomático utilizarlas para implementar la asignación condicional. [13]
mascota = input ( "Ingresa el tipo de mascota que quieres nombrar: " ) mascotas_conocidas = { "Perro" : "Fido" , "Gato" : "Miau" , "Pájaro" : "Tweety" , } mi_nombre = mascotas_conocidas [ mascota ]
En los lenguajes que tienen funciones anónimas o que permiten a un programador asignar una función nombrada a una referencia de variable, el flujo condicional se puede implementar utilizando un hash como tabla de despacho .
Una alternativa a las instrucciones de bifurcación condicional es la predicación . La predicación es una característica arquitectónica que permite que las instrucciones se ejecuten condicionalmente en lugar de modificar el flujo de control .
Esta tabla hace referencia a la especificación de lenguaje más reciente de cada lenguaje. En el caso de los lenguajes que no tienen una especificación, se hace referencia a la última implementación publicada oficialmente.
else if
case
construcción Ruby, la coincidencia de expresiones regulares es una de las alternativas de control de flujo condicional disponibles. Para ver un ejemplo, consulte esta pregunta de Stack Overflow.CASE
CASE WHEN cond1 THEN expr1 WHEN cond2 THEN expr2 [...] ELSE exprDflt END
if ... else if ... else
CASE
CASE expr WHEN val1 THEN expr1 [...] ELSE exprDflt END
if
está obsoleta en Fortran 90.