Avec l'expression if, vous pouvez prendre des décisions qui modifient le flux du programme. Comme avec d'autres langages de programmation, l'expression if de Verse prend en charge l'exécution conditionnelle, mais dans Verse, les conditions utilisent la réussite et l'échec pour motiver la décision.
Par exemple, vous pouvez écrire un code qui définit la hauteur de chute qu'un joueur peut faire avant de subir des dégâts.
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()Dans cet exemple, si PlayerFallHeight est supérieur à trois mètres, la condition réussit et DealDamage() est exécuté avant que la hauteur de chute du joueur ne soit réinitialisée. Sinon, la condition échoue et le joueur ne subit aucun dégât, mais sa hauteur de chute est réinitialisée.
if
L'exemple de la hauteur de chute du joueur utiliserait la syntaxe suivante :
expression0
if (test-arg-block):
expression1
expression2Après avoir exécuté expression0, le programme Verse entre dans le bloc if. Si test-arg-block réussit, le programme Verse exécute expression1, qui peut être une expression ou un bloc d'expressions. Sinon, si test-arg-block échoue, le programme Verse ignore expression1 et n'exécute qu'expression2.
Diagramme de flux pour la logique du bloc if.
if ... else
Vous pouvez également spécifier une expression à exécuter lorsque l'expression if échoue.
Par exemple, le joueur devrait obtenir une capacité de double saut s'il tombe de moins de trois mètres et si son compteur de saut est à 100 %. Mais s'il tombe de plus de trois mètres ou si leur compteur de saut n'est pas à 100 %, le personnage battra des bras pour indiquer au joueur qu'il ne peut pas faire de double saut.
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!
Dans cet exemple, la condition if évalue si PlayerFallHeight est inférieure à trois mètres et si JumpMeter est égal à 100 %. Si la condition réussit, ActivateDoubleJump() et ZeroPlayerFallHeight() sont exécutés avant SetDoubleJumpCooldown().
Si la condition if échoue, l'expression ActivateFlapArmsAnimation() suivant else est exécutée avant SetDoubleJumpCooldown().
Syntaxiquement, l'exemple if-else ressemble à ceci :
expression0
if (test-arg-block):
expression1
else:
expression2
expression3Diagramme de flux pour la logique du bloc if-else.
if ... else if ... else
Si un joueur a 100 % de bouclier lorsqu'il tombe de plus de trois mètres, il subira le maximum de dégâts, mais survivra. Puis, modifions la règle qui donne aux joueurs une capacité de double saut, de telle sorte que les joueurs n'obtiennent le double saut que s'ils tombent de moins de trois mètres et si leur compteur de saut est supérieur à 75 %.
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
Syntaxiquement, l'exemple if-else if-else ressemble à ceci :
expression0
if (test-arg-block0):
expression1
else if (test-arg-block1):
expression2
else:
expression3
expression4Diagramme de flux pour la logique du bloc if-else if-else.
if ... then
Vous pouvez écrire n'importe quelle condition if des exemples précédents sur plusieurs lignes sans changer leur fonctionnement :
expression0
if:
test-arg-block
then:
expression1
expression2Le bloc de code test-arg-block peut contenir une ou plusieurs lignes de conditions, mais elles doivent toutes réussir à exécuter expression1 avant expression2, auquel cas seule expression2 sera exécutée.
L'exemple de la section if ... else réécrit dans ce format ressemble à ceci :
var PlayerFallHeight : float = CalculatePlayerFallHeight()
if:
PlayerFallHeight < 3.0
JumpMeter = 100
then:
# Perform a double jump.
ActivateDoubleJump()
# Reset the player’s fall height.
ZeroPlayerFallHeight()
Expression d'une seule ligne
Vous pouvez écrire if else en tant qu'expression d'une seule ligne, semblable aux opérateurs ternaires d'autres langages de programmation. Par exemple, si vous voulez attribuer une valeur Recharge maximale ou minimale en fonction du paramètre ShieldLevel du joueur, vous pouvez écrire le code Verse suivant :
Recharge : int = if(ShieldLevel < 50) then GetMaxRecharge() else GetMinRecharge()Exigences relatives aux prédicats
Le prédicat du if, qui est l'expression entre parenthèses (), diffère des autres langages de programmation dans la mesure où il ne lui est pas demandé de renvoyer une variable booléenne (appelée logic dans Verse). Au lieu de cela, il est attendu que le prédicat ait l'effet decides (notez que bien que le sous-typage permette normalement un sous-ensemble d'effets dans des emplacements permettant un ensemble d'effets, il exige que l'effet global du prédicat inclue decides). L'effet est retiré de l'étendue environnante. Autrement dit, l'effet decides de toutes les opérations du prédicat if est consommé par la construction if. Par exemple, dans le code ci-dessous, Main n'a pas l'effet decides, bien qu'il invoque Foo, qui l'a.
Foo()<transacts><decides> : void = {}
Bar() : void = {}
Main() : void =
if (Foo[]):
Bar()En effet, plutôt que d'utiliser une entrée logic de if pour choisir la branche à prendre, la réussite des opérations contenues dans le prédicat de if est utilisée pour décider de la branche appropriée : la branche then si toutes les opérations réussissent, la branche else (le cas échéant) si des opérations échouent. Notez que cela signifie que des opérations arbitraires peuvent être utilisées dans le prédicat if, y compris l'introduction de constantes. Par exemple :
Main(X : int) : void =
Y = array{1, 2, 3}
if:
Z0 := Y[X]
Z1 := Y[X + 1]
then:
Use(Z0)
Use(Z1)En d'autres termes, l'étendue de la branche then inclut tous les noms introduits dans le prédicat if.
Comportement transactionnel
Une autre déviation de if par rapport aux autres langages de programmation est le comportement transactionnel du prédicat de if. Le prédicat de if ne doit pas avoir l'effet no_rollback (implicitement utilisé par toutes les fonctions qui ne spécifient pas explicitement transacts, varies ou computes). En effet, en cas d'échec du prédicat, toutes les opérations effectuées pendant l'exécution du prédicat (à l'exception de toute opération ayant un impact sur des ressources extérieures à l'exécution, comme les entrées/sorties de fichiers ou l'écriture sur console) sont annulées avant l'exécution de la branche else. Par exemple :
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 fonction Foo(-1) renvoie 0, tandis que Foo(1) renvoie 1. En effet, bien que l'appel à Incr ait lieu avant le test de X > 0, la mutation de Y qu'il provoque est annulée avant l'exécution de la branche else. Notez que Incr a dû spécifier manuellement l'effet transacts. Par défaut, le comportement transactionnel n'est pas fourni, indiqué par l'effet implicite no_rollback, mais il peut être ajouté en spécifiant l'effet transacts manuellement (en remplaçant l'effet implicite no_rollback).