Com a expressão if, você pode tomar decisões que alteram o fluxo do programa. Como em outras linguagens de programação, a expressão if em Verse é compatível com a execução condicional. Mas, em Verse, as condições utilizam sucesso e falha para orientar as decisões.
Por exemplo, você pode escrever um código que define a altura que um jogador pode cair antes de sofrer danos.
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()Neste exemplo, se PlayerFallHeight for maior que três metros, a condição será bem-sucedida e DealDamage() será executada antes que a altura de queda do jogador seja redefinida. Caso contrário, a condição falhará e, portanto, o jogador não sofrerá danos, mas a altura de queda do jogador será redefinida.
if
O exemplo de altura de queda do jogador usaria a seguinte sintaxe:
expression0
if (test-arg-block):
expression1
expression2Depois de executar expression0, o programa em Verse inclui o if-block. Se test-arg-block tiver sucesso, o programa em Verse executa a expression1, que pode ser uma expressão ou um bloco de expressões. Caso contrário, se test-arg-block falhar, o programa em Verse ignorará expression1 e executará somente expression2.
Fluxograma da lógica do if-block.
if... else
Você também pode especificar uma expressão a ser executada quando a expressão if falhar.
Por exemplo, o jogador deve ganhar uma habilidade de salto duplo se cair menos de três metros e se o medidor de salto estiver em 100 por cento. Porém, se ele cair mais de três metros ou se o medidor de salto não estiver em 100%, os braços do personagem sacudirão para que o jogador saiba que não pode pular duas vezes.
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!
Neste exemplo, a condição if avalia se PlayerFallHeight é menor que três metros e se JumpMeter é igual a 100 por cento. Se a condição tiver sucesso, ActivateDoubleJump() e ZeroPlayerFallHeight() serão executadas antes de SetDoubleJumpCooldown().
Se a condição if falhar, a expressão ActivateFlapArmsAnimation() depois de else será executada antes de SetDoubleJumpCooldown().
Sintaticamente, o exemplo if-else tem a seguinte aparência:
expression0
if (test-arg-block):
expression1
else:
expression2
expression3Fluxograma da lógica de if-else-block.
if... else if... else
Se um jogador tiver 100 por cento de escudos quando cair mais de três metros, deverá sofrer o máximo de dano, mas ainda assim sobreviver. Então, vamos modificar a regra que dá ao jogador a habilidade de salto duplo, de forma que ele só ganhe o salto duplo se cair menos de três metros e se o medidor de salto estiver acima de 75 por cento.
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
Sintaticamente, o exemplo if-else if-else tem a seguinte aparência:
expression0
if (test-arg-block0):
expression1
else if (test-arg-block1):
expression2
else:
expression3
expression4Fluxograma da lógica if-else if-else-block.
if... then
Você pode escrever qualquer uma das condições if nos exemplos anteriores em várias linhas sem alterar a forma como elas funcionam:
expression0
if:
test-arg-block
then:
expression1
expression2O bloco de código test-arg-block pode conter uma ou mais linhas de condições, mas todas elas devem executar expression1 com êxito antes de expression2. Caso contrário, somente expression2 será executada.
O exemplo de if... A seção "if... else" reescrita nesse formato tem a seguinte aparência:
var PlayerFallHeight : float = CalculatePlayerFallHeight()
if:
PlayerFallHeight < 3.0
JumpMeter = 100
then:
# Perform a double jump.
ActivateDoubleJump()
# Reset the player’s fall height.
ZeroPlayerFallHeight()
Expressão de linha única
Você pode escrever if else como uma expressão de linha única, semelhante a operadores ternários em outras linguagens de programação. Por exemplo, se quiser atribuir um valor máximo ou mínimo de Recharge com base no ShieldLevel de um jogador, é possível escrever o seguinte código em Verse:
Recharge : int = if(ShieldLevel < 50) then GetMaxRecharge() else GetMinRecharge()Requisitos de predicado
O predicado de , que é a expressão entre parênteses (), é diferente de outras linguagens de programação, pois não se espera que ele retorne um booleano (chamado de logic em Verse). Em vez disso, espera-se que o predicado tenha o efeito decides (observe que, embora a subtipagem normalmente permita um subconjunto de efeitos em lugares que permitem um conjunto de efeitos, "if" exige que o efeito geral do predicado inclua decides). O efeito é removido do escopo circundante. Ou seja, o efeito decides de todas as operações no predicado de if é consumido pela construção de if. Por exemplo, no código abaixo, Main não tem o efeito decides, embora invoque Foo, que tem esse efeito.
Foo()<transacts><decides> : void = {}
Bar() : void = {}
Main() : void =
if (Foo[]):
Bar()Isso ocorre porque, em vez de usar uma entrada logic em if para escolher qual ramificação será usada, o sucesso das operações contidas no predicado de if é usado para decidir a ramificação apropriada: a ramificação then se todas as operações tiverem sucesso, a ramificação else (se houver) se alguma operação falhar. Observe que isso significa que operações arbitrárias podem ser usadas no predicado de if, incluindo a introdução de constantes. Por exemplo:
Main(X : int) : void =
Y = array{1, 2, 3}
if:
Z0 := Y[X]
Z1 := Y[X + 1]
then:
Use(Z0)
Use(Z1)Dito de outra forma, o escopo da ramificação then inclui quaisquer nomes introduzidos no predicado de if.
Comportamento transacional
Outro desvio de if em relação a outras linguagens de programação é o comportamento transacional do predicado para if. O predicado para if não deve ter o efeito no_rollback (usado implicitamente por todas as funções que não especificam explicitamente transacts, varies ou computes). Isso ocorre porque, caso o predicado falhe, todas as operações realizadas durante a execução do predicado (exceto qualquer operação que afete recursos fora do tempo de execução, como E/S de arquivo ou gravação no console) são desfeitas antes da execução da ramificação else. Por exemplo:
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)
A função Foo(-1) retorna 0, enquanto Foo(1) retorna 1. O que ocorre porque, embora a chamada para Incr ocorra antes do teste de X > 0, a mutação de Y que ela causa é desfeita antes da execução da ramificação else. Observe que Incr teve que especificar manualmente o efeito transacts. Por padrão, o comportamento transacional não é fornecido, indicado pelo efeito implícito no_rollback, mas pode ser adicionado especificando o efeito transacts manualmente (substituindo o efeito no_rollback implícito).