Con la expresión if, puedes tomar decisiones que cambian el flujo del programa. Como en otros lenguajes de programación, la expresión if en Verse admite ejecuciones condicionales pero, en Verse, las condiciones usan éxito o fracaso para impulsar la decisión.
Por ejemplo, puedes escribir un código que defina la altura de caída que puede tener un jugador antes de recibir daño.
var PlayerFallHeight : float = CalculatePlayerFallHeight()
# Players take damage if they fall more than 3 meters
if (PlayerFallHeight > 3.0):
DealDamage()
# Reset the player’s fall height
ZeroPlayerFallHeight()En este ejemplo, si PlayerFallHeight es mayor a tres metros, entonces la condición tiene éxito, y DealDamage() se ejecuta antes de que se restablezca la altura de caída del jugador. De lo contrario, la condición falla, por lo que el jugador no sufre ningún daño, pero la altura de caída del jugador se restablece.
if
El ejemplo de la altura de la caída del jugador utilizaría la siguiente sintaxis:
expression0
if (test-arg-block):
expression1
expression2Después de ejecutar expression0, el programa Verse ingresa al bloque if. Si test-arg-block tiene éxito, entonces el programa Verse ejecuta expression1, que puede ser una expresión o un bloque de expresiones. De lo contrario, si test-arg-block falla, el programa Verse omite expression1 y solo ejecuta expression2.
Diagrama de flujo de la lógica del bloque if.
if… else
También puedes especificar una expresión que se ejecute cuando la expresión de condición if falla.
Por ejemplo, el jugador debe obtener la capacidad de doble salto si cae menos de tres metros y si su medidor de salto está al 100 por ciento. Pero si cae más de tres metros o su medidor de salto no está al 100 %, los brazos del personaje se agitarán para hacerle saber al jugador que no puede realizar un doble salto.
var PlayerFallHeight : float = CalculatePlayerFallHeight()
if (PlayerFallHeight < 3.0 and JumpMeter = 100):
# Perform a double jump.
ActivateDoubleJump()
# Reset the player’s fall height.
ZeroPlayerFallHeight()
else:
# Flap the character’s arms to tell the player they
# cannot double jump right now!
En este ejemplo, la condición if evalúa si PlayerFallHeight es inferior a tres metros y si JumpMeter es igual al 100 por ciento. Si la condición tiene éxito, ActivateDoubleJump() y ZeroPlayerFallHeight() se ejecutan antes que SetDoubleJumpCooldown().
Si la condición if falla, la expresión ActivateFlapArmsAnimation() que sigue a else se ejecuta antes que SetDoubleJumpCooldown().
Sintácticamente, el ejemplo if-else se ve así:
expression0
if (test-arg-block):
expression1
else:
expression2
expression3Diagrama de flujo para la lógica de bloque if-else.
if… else if… else
Si un jugador tiene escudos al 100 por ciento cuando cae más de tres metros, debería recibir el máximo daño pero aun así sobrevivir. Y modifiquemos la regla que otorga a los jugadores la capacidad de doble salto, de modo que los jugadores solo obtendrán doble salto si caen menos de tres metros y si su medidor de salto es superior al 75 por ciento.
var PlayerFallHeight : float = CalculatePlayerFallHeight()
if (PlayerFallHeight > 3.0 and shields = 100):
DealMaximalDamage()
return false
else if (PlayerFallHeight < 3.0 and JumpMeter > 75):
ActivateDoubleJump()
return false
else:
return true
Sintácticamente, el ejemplo if-else if-else se ve así:
expression0
if (test-arg-block0):
expression1
else if (test-arg-block1):
expression2
else:
expression3
expression4Diagrama de flujo para la lógica de bloque if-else.
if… entonces
Puedes escribir cualquiera de las condiciones if en los ejemplos anteriores en varias líneas sin cambiar su funcionamiento:
expression0
if:
test-arg-block
then:
expression1
expression2El bloque de código test-arg-block puede contener una o más líneas de condiciones, pero todas deben tener éxito para ejecutar expression1 antes que expression2; de lo contrario, solo se ejecutará expression2.
El ejemplo de la sección if … else reescrito en este formato se ve así:
var PlayerFallHeight : float = CalculatePlayerFallHeight()
if:
PlayerFallHeight < 3.0
JumpMeter = 100
then:
# Perform a double jump.
ActivateDoubleJump()
# Reset the player’s fall height.
ZeroPlayerFallHeight()
Expresión de una sola línea
Puedes escribir un if else como una expresión de una sola línea, similar a los operadores ternarios en otros lenguajes de programación. Por ejemplo, si deseas asignar un valor de recarga máximo o mínimo en función del ShieldLevel de un jugador, puedes escribir el siguiente código de Verse:
Recharge : int = if(ShieldLevel < 50) then GetMaxRecharge() else GetMinRecharge()Requisitos del predicado
El predicado del if, que es la expresión entre paréntesis (), es diferente a otros lenguajes de programación, dado que no se espera que devuelva un valor booleano (llamado logic en Verse). En cambio, se espera que el predicado tenga el efecto decides (ten en cuenta que, aunque la subtipificación normalmente permite un subconjunto de efectos en lugares que permiten un conjunto de efectos, requiere que el efecto general del predicado incluya decides). El efecto se elimina del alcance circundante. Es decir, el efecto decides de todas las operaciones en el predicado if es consumido por la construcción if. Por ejemplo, en el siguiente código, Main no tiene el efecto decides, aunque invoca a Foo, que sí lo tiene.
Foo()<transacts><decides> : void = {}
Bar() : void = {}
Main() : void =
if (Foo[]):
Bar()Esto se debe a que, en lugar de usar una entrada logic para if para elegir qué rama se toma, el éxito de las operaciones contenidas en el predicado de if se usa para decidir la rama apropiada: la rama then, si todas las operaciones tienen éxito; la rama else (si está presente) si alguna operación falla. Ten en cuenta que esto significa que se pueden usar operaciones arbitrarias en el predicado if, incluida la introducción de constantes. Por ejemplo:
Main(X : int) : void =
Y = array{1, 2, 3}
if:
Z0 := Y[X]
Z1 := Y[X + 1]
then:
Use(Z0)
Use(Z1)Dicho de otra manera, el alcance de la rama then incluye cualquier nombre introducido en el predicado if.
Comportamiento transaccional
Otra desviación de if con respecto a otros lenguajes de programación es el comportamiento transaccional del predicado a if. El predicado de if no debe tener el efecto no_rollback (utilizado implícitamente por todas las funciones que no especifican explícitamente transacts, varies o computes). Esto se debe a que, en caso de que el predicado falle, todas las operaciones realizadas durante la ejecución del predicado (a excepción de cualquier operación que afecte a los recursos de construcción fuera del tiempo de ejecución, como la I/O de archivos o la escritura en la consola) se deshacen antes de la ejecución de la rama else. Por ejemplo:
int_ref := class:
var Contents : int
Incr(X : int_ref)<transacts> : void =
set X.Contents += 1
Foo(X : int) : int =
Y := int_ref{Contents := 0}
if:
Incr(Y)
La función Foo(-1) devolverá 0, mientras que Foo(1) devolverá 1. Esto se debe a que, aunque la llamada a Incr ocurre antes de la prueba de X > 0, la mutación de Y que provoca se deshace antes de la ejecución de la rama else. Ten en cuenta que Incr tenía que especificar manualmente el efecto transacts. De forma predeterminada, no se ofrece el comportamiento transaccional, indicado por el efecto no_rollback implícito, pero se puede agregar especificando el efecto transacts manualmente (anulando el efecto no_rollback implícito).