En informática , los condicionales (es decir, declaraciones condicionales , expresiones condicionales y construcciones condicionales ) son construcciones de lenguajes 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 normalmente se implementan 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 declaraciones condicionales son construcciones imperativas ejecutadas para obtener efectos secundarios, mientras que las expresiones condicionales devuelven valores. Muchos lenguajes de programación (como C) tienen declaraciones 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
o if–then–else
se utiliza en muchos lenguajes de programación. Aunque la sintaxis varía de un idioma a otro, la estructura básica (en forma de pseudocódigo ) se ve así:
Si (condición booleana) Entonces (consiguiente)Demás (alternativa)Terminara si
Por ejemplo:
Si stock = 0 entonces mensaje = pedir nuevo stockDemás mensaje= hay stockTerminara 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 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 sigue después constituyen un enunciado condicional , que tiene significado intrínseco (por ejemplo, expresar una regla lógica coherente) pero no tiene valor intrínseco.
Cuando un intérprete encuentra un If
, espera una condición booleanax > 0
(por ejemplo, , que significa "la variable x contiene un número mayor que cero") y evalúa esa condición. Si la condición es , se ejecutan true
las declaraciones que siguen a . 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 ninguna else
rama, después del archivo end If
.
Después de ejecutar cualquiera de las ramas, el control vuelve al punto posterior al end If
.
En los primeros lenguajes de programación, especialmente algunos dialectos de BASIC en las computadoras domésticas de la década de 1980 , una if–then
declaración solo podía contener GOTO
declaraciones (equivalente a una instrucción de rama ). Esto llevó a un estilo de programación difícil de leer conocido como programación espagueti , y los programas de este estilo se denominan código espagueti . Como resultado, la programación estructurada , que permite colocar declaraciones (virtualmente) arbitrarias en bloques de declaraciones dentro de una if
declaración, ganó popularidad, hasta que se convirtió en la norma incluso en la mayoría de los círculos de programación BÁSICA. Dichos mecanismos y principios se basaron en la familia de lenguajes ALGOL, más antigua pero más avanzada , y los lenguajes similares a ALGOL, como Pascal y Modula-2, influyeron en las variantes BASIC modernas durante muchos años. Si bien es posible usar solo GOTO
declaraciones en if–then
declaraciones para escribir programas que no sean código espagueti y que estén tan bien estructurados y legibles como los programas escritos en un lenguaje de programación estructurado, la programación estructurada lo hace más fácil y lo impone. 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 para las declaraciones anidadas if–then
, los lenguajes de programación clásicos como ALGOL 60 tuvieron dificultades para definir a qué declaración específica apuntar. Sin límites claros para qué declaración es cuál, una else
palabra clave podría apuntar a cualquier if–then
declaración anterior en el nido, tal como se analiza.
si a entonces si b entonces s si no s2
se puede analizar como
si a entonces ( si b entonces s) si no s2
o
si a entonces ( si b entonces s sino s2)
dependiendo de si else
está asociado al primero if
o al segundo if
. Esto se conoce como el problema de los demás pendientes y se resuelve de varias maneras, según el idioma (comúnmente mediante la end if
declaración o {...}
los corchetes).
Al utilizar else if
, es posible combinar varias condiciones. Sólo se ejecutarán las declaraciones que siguen a la primera condición que se considere verdadera. Se omitirán todas las demás declaraciones.
si condición entonces - declaraciones elseif condición entonces - más declaraciones elseif condición entonces - más declaraciones;...else -- otras declaraciones; terminara 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)elseif descuento <21% entonces imprimir (tienes que pagar $20)elseif descuento <31% entonces imprimir (tienes que pagar $10)terminara si ;
En el ejemplo anterior, si el descuento es del 10 %, entonces la primera declaración if se evaluará como verdadera y se imprimirá "tienes que pagar $30". Todas las demás declaraciones debajo de la primera declaración if se omitirán.
La elseif
declaración, en el lenguaje Ada , por ejemplo, es simplemente azúcar sintáctico 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 utiliza la elseif
palabra clave [1] tanto para sus llaves como para su sintaxis de dos puntos. Perl proporciona la palabra clave elsif
para evitar la gran cantidad de llaves que requerirían las declaraciones múltiples if
y else
. Python usa la palabra clave especial elif
porque la estructura se indica mediante sangría en lugar de llaves, por lo que un uso repetido de else
y if
requeriría una mayor sangría después de cada condición. Algunas implementaciones de BASIC , como Visual Basic , [2] también lo utilizan ElseIf
. De manera similar, los shells UNIX anteriores (posteriormente reunidos en la sintaxis del shell POSIX [3] ) también usan elif, pero dan 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 está presente en los muchos derivados sintácticos de C, como Java , ECMAScript y pronto. Esto funciona porque en estos lenguajes, cualquier declaración (en este caso ...) puede seguir a un condicional sin estar encerrada en un bloque.if cond
Esta elección de diseño tiene un ligero "coste". Cada else if
rama efectivamente agrega 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 en la secuencia de condicionales prueban el valor de una sola expresión (por ejemplo, if x=0
... else if x=1
... else if x=2
...), una alternativa es la declaración de cambio , también llamada declaración de caso o declaración de selección. Por el contrario, en lenguajes que no tienen una declaración de cambio, éstas pueden producirse mediante una secuencia de else if
declaraciones.
Muchos idiomas admiten expresiones if , que son similares a las declaraciones if, pero devuelven un valor como resultado. Por lo tanto, son expresiones verdaderas (que se evalúan como un valor), no declaraciones (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 si no 2
En dialectos de Lisp – Scheme , Racket y Common Lisp – el primero de los cuales se inspiró en gran medida en ALGOL:
;; Esquema ( defina mivariable ( si ( > x 12 ) 1 2 )) ; Asigna 'mivariable' a 1 o 2, dependiendo del valor de 'x'
;; Lisp común ( let (( x 10 )) ( setq mivariable ( if ( > x 12 ) 2 4 ))) ; Asigna 'mivariable' a 2
En Haskell 98, solo hay una expresión if , no una 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.
Debido a que Haskell es vago , es posible escribir estructuras de control, como if , como expresiones ordinarias; la evaluación diferida significa que una función if puede evaluar solo la condición y la rama adecuada (donde un lenguaje estricto evaluaría las tres). Se puede escribir así: [5]
if' :: Bool -> a -> a -> a if' Verdadero x _ = x if' 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 incluir en expresiones, a diferencia de las sentencias if, en lenguajes tipo C:
mi_variable = x > 10 ? "foo" : "barra" ; // En lenguajes tipo C
que se puede comparar 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 requeriría más de una línea de código (según las convenciones de diseño típicas) y requeriría mencionar "mi_variable" dos veces:
si ( x > 10 ) mi_variable = "foo" ; else mi_variable = "barra" ;
Algunos argumentan que la declaración explícita si/entonces 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 repetición.
x = Ventana de texto . ReadNumber () Si ( x > 10 ) Entonces TextWindow . WriteLine ( "Mi variable se llama 'foo'." ) De lo contrario TextWindow . WriteLine ( "Mi variable se llama 'barra'." ) EndIf
Primero, cuando el usuario ejecuta el programa, aparece un cursor esperando que el lector escriba un número. Si ese número es mayor que 10, el texto "Mi variable se llama 'foo'". se muestra en la pantalla. Si el número es menor que 10, aparecerá el mensaje "Mi variable se llama 'barra'". está impreso en la pantalla.
En Visual Basic y algunos 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 siempre se evalúan tanto la rama verdadera como la falsa; es solo que el resultado de uno de ellos se desecha, mientras que el resultado del otro lo devuelve la función IIf.
En Tcl if
no es una palabra clave sino una función (en Tcl se conoce como comando o proc
). Por ejemplo
si { $x > 10 } { pone "¡Foo!" }
invoca una función llamada if
pasando 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 alcance de la persona que llama. [7]
Este comportamiento es posible mediante el uso de los comandos uplevel
y expr
:
Como if
en realidad es una función, también devuelve un valor:
En Rust , if
siempre es una expresión. Se evalúa según el valor de cualquier rama que se ejecute, o según el tipo de unidad ()
si no se ejecuta ninguna rama. Si una rama no proporciona un valor de retorno, se evalúa ()
de forma predeterminada. Para garantizar que if
se conozca el tipo de expresión en el momento de la compilación, cada rama debe evaluarse como un valor del mismo tipo. Por esta razón, una else
rama es efectivamente obligatoria a menos que las otras ramas evalúen como ()
, porque una if
sin an else
siempre puede evaluarse como ()
por defecto. [10]
// Asigna algún valor a mi_variable, dependiendo del valor de x let mi_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 protegido (GCL) de Edsger Dijkstra admite la ejecución condicional como una lista de comandos que consta de una protección con valor booleano (correspondiente a una condición ) y su declaración correspondiente. En GCL, se evalúa exactamente una de las declaraciones cuyo guardia es verdadero, pero cuál es arbitrario. en este codigo
si G0 → S0 □ G1 → S1... □ Gn → Snfi
los G i son los guardias y los S i son las declaraciones. Si ninguna de las garantías es verdadera, el comportamiento del programa no está definido.
GCL está destinado principalmente a 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 if aritmética que salta a una de tres etiquetas dependiendo de si su argumento e es e < 0, e = 0, e > 0. Esta fue la declaración condicional más antigua 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.
IF ( e . LT . 0 ) GOTO etiqueta 1 IF ( e . EQ . 0 ) GOTO etiqueta 2 IF ( e . GT . 0 ) GOTO etiqueta 3
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
los enunciados aritméticos hacen referencia al siguiente enunciado 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 ramificación tenía tres direcciones para esos tres estados. Otras computadoras tendrían registros de "bandera" como positivo, cero, negativo, par, desbordamiento, acarreo, asociados con las últimas operaciones aritméticas y usarían instrucciones como 'Branque si el acumulador es negativo' y luego 'Branque si el acumulador es cero' o similares. Tenga en cuenta que la expresión se evalúa solo una vez y, en casos como la aritmética de enteros donde puede ocurrir un desbordamiento, también se considerarán 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 y 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 ( "¡Tienes cara!" ); } más { consola . log ( "¡Tienes Tails!" ); }
El ejemplo anterior toma el condicional de Math.random() < 0.5
which produce true
si un valor flotante aleatorio entre 0 y 1 es mayor que 0,5. La declaración lo usa para elegir aleatoriamente entre salida You got Heads!
o You got Tails!
a la consola. Las declaraciones else y else-if también se pueden encadenar después de la llave de la declaración que la precede tantas veces como sea necesario, como se muestra a continuación:
varx = Matemáticas . aleatorio (); si ( x < 1/3 ) { consola . log ( "¡Una persona ganó!" ); } else if ( x < 2/3 ) { consola . log ( "¡Dos personas ganaron!" ); } más { consola . log ( "¡Es un empate a tres!" ); }
En el cálculo Lambda , el concepto de condicional si-entonces-si no se puede expresar mediante las siguientes expresiones:
verdadero = λx. λy. Xfalso = λx. λy. yifThenElse = (λc. λx. λy. (cxy))
nota : si a ifThenElse se le pasan dos funciones como condicionales izquierdo y derecho; También es necesario pasar 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 los números se pueden usar sin definición (como Lisp, matemáticas tradicionales en papel, etc.), lo anterior se puede expresar como un cierre único a continuación:
(( λtrue. λfalse. λifThenElse. ( ifThenElse true 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 alcance 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 resultadoComputación = (( _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 en el que se suponen números.
El primer ejemplo muestra la primera rama que se está tomando, mientras que el segundo ejemplo muestra la segunda rama que se está tomando.
(( λtrue. λfalse. λifThenElse. ( ifThenElse true ( λFirstBranch. FirstBranch ) ( λSecondBranch. SecondBranch )) )( λx. λy. x )( λx. λy. y )( λc. λl. λr. c l r )) (( λtrue. λfalse. λifThenElse. ( ifThenElse false ( λFirstBranch. FirstBranch ) ( λSecondBranch. SecondBranch )) )( λx. λy. x )( λx. λy. y )( λc. λl. λr. c l r ))
Smalltalk utiliza una idea similar para sus representaciones de verdadero y falso, siendo Verdadero y Falso objetos únicos 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 este artículo, la mayoría de los programas de Haskell usan la construcción sintáctica de azúcar "if a entonces b else c" que, a diferencia de ifThenElse, no compone a menos que se incluya en otra función o se vuelva a implementar. como se muestra en la sección The Haskell de esta página.
Las declaraciones de cambio (en algunos idiomas, declaraciones de casos o ramas multidireccionales) comparan un valor dado con constantes específicas y toman medidas de acuerdo con la primera constante que coincida. Generalmente existe una disposición para que se tome una acción predeterminada ("de lo contrario", "de lo contrario") si ninguna coincidencia tiene éxito. Las sentencias de cambio pueden permitir optimizaciones del compilador , como tablas de búsqueda . En los lenguajes dinámicos, los casos pueden no limitarse a expresiones constantes y pueden extenderse a la coincidencia de patrones , como en el ejemplo del script de shell de la derecha, donde '*)' implementa el caso predeterminado como una expresión regular que coincide con cualquier cadena.
La coincidencia de patrones puede verse como una alternativa tanto a las declaraciones if-then-else como a las case . Está disponible en muchos lenguajes de programación con características de programación funcionales, como Wolfram Language , ML y muchos otros. Aquí hay un ejemplo simple escrito en el lenguaje OCaml :
combinar fruta con | "manzana" -> cocinar pastel | "coco" -> cocinar dango_mochi | "plátano" -> mezclar ;;
El poder de la coincidencia de patrones es la capacidad de hacer coincidir de manera concisa no solo acciones sino también valores con patrones de datos. Aquí hay un ejemplo escrito en Haskell que ilustra ambas características:
mapa _ [] = [] mapa f ( h : t ) = f h : mapa f t
Este código define un mapa de funciones , 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 donde la lista está vacía (simplemente devuelve una lista vacía) y el otro caso donde la lista no está vacía.
La coincidencia de patrones no es siempre estrictamente hablando una construcción de elección, porque en Haskell es posible escribir sólo una alternativa, que se garantiza que siempre coincidirá; en esta situación, no se utiliza como una construcción de elección, sino simplemente como una forma de para vincular nombres a valores. Sin embargo, se utiliza con frecuencia como construcción de elección en los idiomas en los que está disponible.
En lenguajes de programación que tienen matrices asociativas o estructuras de datos comparables, como Python , Perl , PHP u Objective-C , es idiomático usarlos para implementar la asignación condicional. [13]
mascota = entrada ( "Ingrese el tipo de mascota que desea nombrar: " ) mascotas_conocidas = { "Perro" : "Fido" , "Gato" : "Meowsles" , "Pájaro" : "Piolín" , } mi_nombre = mascotas_conocidas [ mascota ]
En lenguajes que tienen funciones anónimas o que permiten a un programador asignar una función con nombre a una referencia variable, el flujo condicional se puede implementar utilizando un hash como tabla de distribución .
Una alternativa a las instrucciones de rama condicional es la predicación . La predicció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 idioma más reciente de cada idioma. Para 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 se encuentra entre las alternativas de control de flujo condicional disponibles. Para ver un ejemplo, consulte esta pregunta de desbordamiento de pila.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.