Condicional (programación informática) - Conditional (computer programming)

Diagrama de flujo If-Then-Else
Un diagrama de flujo anidado "Si-Entonces-Else"

En informática , los condicionales (es decir, declaraciones condicionales , expresiones condicionales y construcciones condicionales ) son comandos del lenguaje de programación para manejar decisiones. Específicamente, los condicionales realizan diferentes cálculos o acciones dependiendo de si una condición booleana definida por el programador se evalúa como verdadera o falsa. En términos de flujo de control , la decisión siempre se logra alterando selectivamente el flujo de control en función de alguna condición (aparte del caso de predicación de rama ).

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 .

Terminología

En los lenguajes de programación imperativos , el término " declaración condicional " se usa generalmente, mientras que en la programación funcional , se prefieren los términos " expresión condicional " o "construcción condicional", porque todos estos términos tienen significados distintos.

Si – entonces (–else)

La if–thenconstrucción (a veces llamada if–then–else) es común 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í:

If (boolean condition) Then
    (consequent)
Else
    (alternative)
End If

Por ejemplo:

If stock=0 Then
    message= order new stock
Else
    message= there is stock
End If

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 ser sustituida por cualquiera de los valores Trueo False) pero no tiene un significado intrínseco. En contraste, la combinación de esta expresión, el Ify que la Thenrodea, y el consecuente que sigue después constituyen un enunciado condicional , que tiene un significado intrínseco (por ejemplo, que expresa una regla lógica coherente) pero no un valor intrínseco.

Cuando un intérprete encuentra una If, espera una condición booleana (por ejemplo, x > 0que significa "la variable x contiene un número mayor que cero") y evalúa esa condición. Si la condición es true, thense ejecutan las declaraciones que siguen a . 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 elserama, después de end If.

Después de que se haya ejecutado cualquiera de las ramas, el control vuelve al punto después de end If.

Historia y desarrollo

En los primeros lenguajes de programación, especialmente en algunos dialectos de BASIC en las computadoras domésticas de la década de 1980 , una if–thendeclaración solo podía contener GOTOdeclaraciones (equivalente a una instrucción de rama ). Esto llevó 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 colocar sentencias (virtualmente) arbitrarias en bloques de sentencias dentro de una ifsentencia, 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 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 GOTOdeclaraciones en if–thendeclaraciones para escribir programas que no son 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 hace que esto sea más fácil y lo refuerza. Las if–then–elsedeclaraciones estructuradas 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 .

El problema de "colgar más"

La elsepalabra clave está diseñada para apuntar a una if–thendeclaración específica que la precede, pero para las if–then declaraciones anidadas , los lenguajes de programación clásicos como ALGOL 60 lucharon por definir a qué declaración específica apuntar. Sin límites claros para qué declaración es cuál, una elsepalabra clave podría apuntar a cualquier if–thendeclaración anterior en el nido, como se analiza.

if a then if b then s else s2

se puede analizar como

if a then (if b then s) else s2

o

if a then (if b then s else s2)

dependiendo de si elseestá asociado con el primero ifo el segundo if. Esto se conoce como el problema colgando else y se resuelve de varias formas, dependiendo del idioma (comúnmente a través de la end ifdeclaración o {...}corchetes).

De lo contrario si

Al usar else if, es posible combinar varias condiciones. Solo se ejecutarán las declaraciones que sigan la primera condición que se considere verdadera. Se omitirán todas las demás declaraciones.

if condition then
   --statements
elseif condition then
    -- more statements
elseif condition then
    -- more statements;
...
else
    -- other statements;
end if;

Por ejemplo, para una tienda que ofrece hasta un 30% de descuento en un artículo:

if discount < 11% then
    print (you have to pay $30)
elseif discount<21% then
    print (you have to pay $20)
elseif discount<31% then
    print (you have to pay $10)
end if;

La elseifdeclaración, en el Ada idioma, por ejemplo, es simplemente azúcar sintáctico para elseseguido por if. En Ada, la diferencia es que solo end ifse necesita uno, si se usa en elseiflugar de elseseguido de if. PHP usa la elseifpalabra clave tanto para sus corchetes como para la sintaxis de dos puntos. Perl proporciona la palabra clave elsifpara evitar la gran cantidad de llaves que requerirían varias declaraciones ify else. Python usa la palabra clave especial elifporque la estructura se denota por sangría en lugar de llaves, por lo que un uso repetido de elsey ifrequeriría una mayor sangría después de cada condición. Algunas implementaciones de BASIC , como Visual Basic , ElseIftambién usan . De manera similar, los shells de UNIX anteriores (luego reunidos en la sintaxis de shell de POSIX) también usan elif, pero dando la opción de delimitar con espacios, saltos de línea o ambos.

Sin embargo, en muchos lenguajes descendientes más directamente de Algol, como Simula , Pascal , BCPL y C , esta sintaxis especial para la else ifconstrucció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 idiomas, ninguna sola declaración (en este caso ...) puede seguir un condicional sin ser encerrado en un bloque. if cond

Esta elección de diseño tiene un ligero "coste". Cada else iframa agrega efectivamente un nivel de anidación adicional. Esto complica el trabajo para el compilador (o las personas que escriben el compilador), porque el compilador debe analizar e implementar else ifcadenas arbitrariamente largas de forma recursiva.

Si todos los términos en 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 instrucción de cambio , también llamada instrucción de caso o instrucción de selección. Por el contrario, en los lenguajes que no tienen una instrucción de cambio, estos pueden producirse mediante una secuencia de else ifdeclaraciones.

Expresiones if-then-else

Muchos lenguajes admiten expresiones if , que son similares a las declaraciones if, pero devuelven un valor como resultado. Por lo tanto, son expresiones verdaderas (que evalúan un valor), no declaraciones (que pueden no estar permitidas en el contexto de un valor).

Familia Algol

ALGOL 60 y algunos otros miembros de la familia ALGOL permiten if–then–elsecomo expresión:

  myvariable := if x > 20 then 1 else 2

Dialectos Lisp

En dialectos de Lisp  - Scheme , Racket y Common Lisp  - el primero de los cuales se inspiró en gran medida en ALGOL:

;; Scheme
(define myvariable (if (> x 12) 1 2))   ; Assigns 'myvariable' to 1 or 2, depending on the value of 'x'
;; Common Lisp
(let ((x 10))
  (setq myvariable (if (> x 12) 2 4)))  ; Assigns 'myvariable' to 2

Haskell

En Haskell 98, solo hay una expresión if , una declaración no if , y la elseparte es obligatoria, ya que cada expresión debe tener algún valor. 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 si , como expresiones ordinarias; la evaluación perezosa 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í:

if' :: Bool -> a -> a -> a
if' True x _ = x
if' False _ y = y

Lenguajes similares a C

Los lenguajes C y C-like tienen un operador ternario especial ( ?:) Para expresiones condicionales con una función que puede ser descrita por una plantilla como esta:

condition ? evaluated-when-true : evaluated-when-false

Esto significa que se puede insertar en expresiones, a diferencia de las sentencias if, en lenguajes similares a C:

my_variable = x > 10 ? "foo" : "bar";  // In C-like languages

que se puede comparar con las expresiones if-then-else de la familia Algol (en contraste con una declaración ) (y similar en Ruby y Scala, entre otras).

Para lograr lo mismo usando una declaración if, esto tomaría más de una línea de código (según las convenciones de diseño típicas) y requeriría mencionar "my_variable" dos veces:

if (x > 10)
    my_variable = "foo";
else
    my_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, 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.

Pequeño Básico

x = TextWindow.ReadNumber()
If (x > 10) Then
    TextWindow.WriteLine("My variable is named 'foo'.")
Else
    TextWindow.WriteLine("My variable is named 'bar'.")
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, el mensaje "Mi variable se llama 'barra'". está impreso en la pantalla.

Visual Basic

En Visual Basic y algunos otros lenguajes, IIfse proporciona una función llamada , que se puede usar 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; es solo que el resultado de uno de ellos se desecha, mientras que el resultado del otro es devuelto por la función IIf.

Tcl

En Tcl if no es una palabra clave sino una función (en Tcl conocida como comando o proc). Por ejemplo

if {$x > 10} {
   puts "Foo!"
}

invoca una función llamada ifpasando 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 corchetes 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 iffunció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 los llamadores.

Este comportamiento es posible mediante los comandos uplevely expr:

Uplevel hace posible implementar nuevas construcciones de control como procedimientos Tcl (por ejemplo, uplevel podría usarse para implementar la construcción while como un procedimiento Tcl).

Debido a ifque en realidad es una función, también devuelve un valor:

El valor de retorno del comando es el resultado de la secuencia de comandos del cuerpo que se ejecutó, o una cadena vacía si ninguna de las expresiones era distinta de cero y no había cuerpoN.

Oxido

En Rust , ifsiempre es una expresión. Evalúa el valor de cualquier rama que se ejecute, o 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 ifse conozca el tipo de la expresión en el momento de la compilación, cada rama debe evaluar un valor del mismo tipo. Por esta razón, una elserama es efectivamente obligatoria a menos que las otras ramas evalúen a (), porque un ifsin un elsesiempre puede evaluar a ()de forma predeterminada.

// Assign my_variable some value, depending on the value of x
let my_variable = if x > 20 {
    1
} else {
    2
};

// This variant will not compile because 1 and () have different types
let my_variable = if x > 20 {
    1
};

// Values can be omitted when not needed
if x > 20 {
    println!("x is greater than 20");
}

Aritmética si

Hasta Fortran 77 , el lenguaje Fortran tiene una declaración "aritmética if" que está a medio camino entre una IF calculada y una declaración de caso, basada en la tricotomía x <0, x = 0, x > 0. Esta fue la declaración condicional más antigua en Fortran:

IF (e) label1, label2, label3

Donde e es cualquier expresión numérica (no necesariamente un número entero); esto es equivalente a

IF (e .LT. 0) GOTO label1
IF (e .EQ. 0) GOTO label2
GOTO label3

Debido a que este IF aritmético es equivalente a múltiples GOTOdeclaraciones que podrían saltar a cualquier lugar, se considera una declaración de control no estructurada y no debe usarse si se pueden usar declaraciones más estructuradas. En la práctica, se ha observado que la mayoría de los IFenunciados 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 rama 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 'Ramificar si el acumulador es negativo' y luego 'Ramificar si el acumulador es cero' o similar. Tenga en cuenta que la expresión se evalúa solo una vez y, en casos como la aritmética de enteros, donde puede producirse un desbordamiento, también se considerarían los indicadores de desbordamiento o acarreo.

Implementación orientada a objetos en Smalltalk

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 Booleancomo un método abstracto que toma dos parámetros, ambos cierres . Booleantiene dos subclases, Truey False, las cuales definen el método, Trueejecutan solo el primer cierre, Falseejecutan solo el segundo cierre.

var = condition 
    ifTrue: [ 'foo' ]
    ifFalse: [ 'bar' ]

JavaScript

Dos ejemplos en JavaScript :

if (Math.random() < 0.5) {
  console.log("You got Heads!");
} else {
  console.log("You got Tails!");
}

var x = Math.random();
if (x < 1/3) {
  console.log("One person won!");
} else if (x < 2/3) {
  console.log("Two people won!");
} else {
  console.log("It's a three-way tie!");
}

Cálculo lambda

En el cálculo de Lambda , el concepto de un condicional if-then-else se puede expresar mediante las expresiones:

true = λx. λy. x
false = λx. λy. y
ifThenElse = (λc. λx. λy. (c x y))
  1. true toma hasta dos argumentos y una vez que se proporcionan ambos (ver currying ), devuelve el primer argumento dado.
  2. false toma hasta dos argumentos y una vez que se proporcionan ambos (ver currying ), devuelve el segundo argumento dado.
  3. ifThenElse toma hasta tres argumentos y una vez que se proporcionan todos, pasa tanto el segundo como el tercer argumento al primer argumento (que es una función que da dos argumentos y produce un resultado). Esperamos que ifThenElse solo tome verdadero o falso como argumento, los cuales proyectan los dos argumentos dados a su argumento único preferido, que luego se devuelve.

nota : si ifThenElse se pasa dos funciones como condicionales izquierdo y derecho; también es necesario pasar una tupla vacía () al resultado de ifThenElse para llamar realmente a la función elegida; de lo contrario, ifThenElse simplemente devolverá el objeto de la 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 solo cierre 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 el rigor) es:

 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 en el que se asumen números.

El primer ejemplo muestra que se está tomando la primera rama, mientras que el segundo ejemplo muestra que se está tomando la segunda rama.

 ((λ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 usa una idea similar para sus representaciones verdaderas y falsas, siendo True y False objetos únicos que responden a los mensajes ifTrue / ifFalse de manera diferente.

Haskell solía usar este modelo exacto para su tipo booleano, pero en el momento de escribir este artículo, la mayoría de los programas de Haskell usan la construcción sintáctica "if a then b else c" que, a diferencia de ifThenElse, no se compone a menos que esté envuelto en otra función o reimplementado como se muestra en la sección The Haskell de esta página.

Declaraciones de caso y cambio

Las sentencias de cambio (en algunos lenguajes, sentencias de casos o ramas de múltiples vías) comparan un valor dado con constantes especificadas y toman medidas de acuerdo con la primera constante que coincida. Por lo general, existe una disposición para que se realice una acción predeterminada ('si no', '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 estar limitados a expresiones constantes y pueden extenderse a la coincidencia de patrones , como en el ejemplo de script de shell de la derecha, donde el '*)' implementa el caso predeterminado como una expresión regular que coincide con cualquier cadena.

Pascal : C : Secuencia de comandos de shell :
case someChar of
  'a': actionOnA;
  'x': actionOnX;
  'y','z':actionOnYandZ;
  else actionOnNoMatch;
end;
switch (someChar) {
  case 'a': actionOnA; break;
  case 'x': actionOnX; break;
  case 'y':
  case 'z': actionOnYandZ; break;
  default: actionOnNoMatch;
}
case $someChar in 
   a)    actionOnA; ;;
   x)    actionOnX; ;;
   [yz]) actionOnYandZ; ;;
  *)     actionOnNoMatch  ;;
esac

La coincidencia de patrones

La concordancia de patrones puede verse como una alternativa tanto a if-then-else como a declaraciones de casos . 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 :

match fruit with
| "apple" -> cook pie
| "coconut" -> cook dango_mochi
| "banana" -> mix;;

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 estas dos características:

map _ []      = []
map f (h : t) = f h : map 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 (solo 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 solo 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 para vincular nombres a valores. Sin embargo, se utiliza con frecuencia como una construcción de elección en los idiomas en los que está disponible.

Condicionales basados ​​en hash

En los 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.

pet = input("Enter the type of pet you want to name: ")
known_pets = {
    "Dog": "Fido",
    "Cat": "Meowsles",
    "Bird": "Tweety",
}
my_name = known_pets[pet]

En 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 usando un hash como tabla de despacho .

Predicación

Una alternativa a las instrucciones de bifurcación 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 .

Referencia cruzada del sistema de elección

Esta tabla se refiere a la especificación de idioma más reciente de cada idioma. Para los idiomas que no tienen una especificación, se hace referencia a la última implementación publicada oficialmente.

Lenguaje de programación Estructurado si cambiar –seleccionar – caso Aritmética si La coincidencia de patrones
luego demás si no
Ada No No
APL No No
Cáscara de Bash No
C , C ++ Caer a través No No
C# Innecesario No No
COBOL Innecesario No No
Eiffel No No
F# Innecesario No
Fortran 90 No
Ir Innecesario No No
Haskell Necesario Innecesario Si, pero innecesario No
Java Innecesario Caer a través No No
ECMAScript ( JavaScript ) Innecesario Caer a través No No
Mathematica No
Oberon No No
Perl No No
PHP Caer a través No No
Pascal , Objeto Pascal ( Delphi ) Innecesario No No
Pitón No No No
QuickBASIC No No
Rubí No
Oxido Innecesario No
Scala Innecesario Caer a través No
SQL No No
Rápido No
Tcl No
Visual Basic , clásico No No
Visual Basic .NET No No
Windows PowerShell Caer a través No No
  1. ^ Esto se refiere a la coincidencia de patrones como una construcción condicional distinta en el lenguaje de programación, a diferencia del mero soporte de coincidencia de patrones de cadena, comoelsoporte deexpresiones regulares.
  2. 1 2 3 4 5 Lo que se encuentra a menudoelse ifen la familia de lenguajes C, y en COBOL y Haskell, no es una característica del lenguaje, sino un conjunto dedeclaracionesif then elseanidadas e independientescombinadas con un diseño de código fuente particular. Sin embargo, esto también significa que en estos lenguajes no se necesita realmente una construcción else – if distinta.
  3. 1 2 En Haskell y F #, no se necesita una construcción de elección constante separada, porque la misma tarea se puede realizar con la coincidencia de patrones.
  4. ^ En unacaseconstrucción deRuby,lacoincidencia deexpresiones regulares seencuentra entre las alternativas de control de flujo condicional disponibles. Para obtener un ejemplo, consulteestapregunta sobre desbordamiento de pila.
  5. 1 2 SQL tiene dos construcciones similares que cumplen ambos roles, ambos introducidos enSQL-92. UnaCASEexpresión"buscada"CASE WHEN cond1 THEN expr1 WHEN cond2 THEN expr2 [...] ELSE exprDflt ENDfunciona comoif ... else if ... else, mientras que unaCASEexpresión"simple":CASE expr WHEN val1 THEN expr1 [...] ELSE exprDflt ENDfunciona como una declaración de cambio. Para obtener detalles y ejemplos, consulteCase (SQL).
  6. ^ La aritméticaifes obsoleta en Fortran 90.
  7. ^ La coincidencia de patrones se agregó en Ruby 3.0. Algunas construcciones de coincidencia de patrones aún son experimentales.

Ver también

Referencias

enlaces externos