Con l'espressione if, puoi prendere decisioni che cambiano il flusso del programma. Come in altri linguaggi di programmazione, l'espressione if di Verse supporta l'esecuzione condizionale, ma in Verse le condizioni utilizzano la riuscita e l'errore per guidare la decisione.
Ad esempio, puoi scrivere del codice che definisce l'altezza di caduta di un giocatore prima che questi subisca danni.
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()In questo esempio, se PlayerFallHeight è maggiore di tre metri, la condizione riesce e DealDamage() viene eseguito prima che l'altezza di caduta del giocatore venga reimpostata. In caso contrario, la condizione non riesce e il giocatore non subisce alcun danno, ma l'altezza di caduta del giocatore viene reimpostata.
if
L'esempio dell'altezza di caduta del giocatore utilizzerebbe la seguente sintassi:
expression0
if (test-arg-block):
expression1
expression2Dopo aver eseguito expression0, il programma Verse entra in if-block. Se il test-arg-block riesce, allora il programma Verse esegue expression1 che può essere un'espressione o un blocco di espressioni. In caso contrario, se il test-arg-block non riesce, il programma Verse salta expression1 ed esegue solo expression2.
Diagramma di flusso per la logica if-block.
if ... else
Puoi anche specificare un'espressione da eseguire quando l'espressione if non riesce.
Ad esempio, il giocatore deve ottenere l'abilità di doppio salto se cade da meno di tre metri e se il suo metro di salto è al 100%. Ma se il personaggio cade per più di tre metri o se il suo metro di salto non è al 100%, le braccia del personaggio si muoveranno per far capire al giocatore che non può eseguire il doppio 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!
In questo esempio, la condizione di if valuta se PlayerFallHeight è inferiore a tre metri e se JumpMeter è uguale al 100%. Se la condizione riesce, ActivateDoubleJump() e ZeroPlayerFallHeight() vengono eseguiti prima di SetDoubleJumpCooldown().
Se la condizione if non riesce, l'espressione ActivateFlapArmsAnimation() che segue else viene eseguita prima di SetDoubleJumpCooldown().
A livello sintattico, l'esempio if-else si presenta come segue:
expression0
if (test-arg-block):
expression1
else:
expression2
expression3Diagramma di flusso per la logica if-else-block.
if ... else if ... else
Se un giocatore ha il 100% di scudi quando cade per più di tre metri, deve subire il massimo dei danni ma riuscire a sopravvivere. Modifichiamo ora la regola che dà ai giocatori l'abilità del doppio salto in modo che i giocatori ottengano il doppio salto solo se cadono da meno di tre metri e se il loro metro di salto è superiore al 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
A livello sintattico, l'esempio if-else if-else si presenta come segue:
expression0
if (test-arg-block0):
expression1
else if (test-arg-block1):
expression2
else:
expression3
expression4Diagramma di flusso per la logica if-else if-else-block.
if ... then
Puoi scrivere le condizioni if degli esempi precedenti su più righe senza modificare il loro funzionamento:
expression0
if:
test-arg-block
then:
expression1
expression2Il blocco di codice test-arg-block può contenere una o più righe di condizioni, ma tutte devono riuscire a eseguire expression1 prima di expression2, in caso contrario viene eseguita solo expression2.
L'esempio tratto dalla sezione if ... else riscritto in questo formato si presenta come segue:
var PlayerFallHeight : float = CalculatePlayerFallHeight()
if:
PlayerFallHeight < 3.0
JumpMeter = 100
then:
# Perform a double jump.
ActivateDoubleJump()
# Reset the player’s fall height.
ZeroPlayerFallHeight()
Espressione a riga singola
Puoi scrivere un if else come un'espressione a riga singola, simile agli operatori ternari di altri linguaggi di programmazione. Ad esempio, se vuoi assegnare un valore massimo o minimo di Recharge in base a ShieldLevel di un giocatore, puoi scrivere il seguente codice in Verse:
Recharge : int = if(ShieldLevel < 50) then GetMaxRecharge() else GetMinRecharge()Requisiti del predicato
Il predicato di if, che è l'espressione tra parentesi (), è diverso da altri linguaggi di programmazione in quanto non ci si aspetta che restituisca un booleano (chiamato logic in Verse). Invece, ci si aspetta che il predicato abbia l'effetto decides (tieni presente che, anche se la sottotipizzazione permette normalmente un sottoinsieme di effetti in luoghi che permettono un insieme di effetti, if richiede che l'effetto complessivo del predicato includa decides). L'effetto viene rimosso dall'ambito circostante. In altre parole, l'effetto decides di tutte le operazioni nel predicato if viene utilizzato dal costrutto if. Per esempio, nel codice sottostante, Main non ha l'effetto decides, anche se richiama Foo che invece possiede tale effetto.
Foo()<transacts><decides> : void = {}
Bar() : void = {}
Main() : void =
if (Foo[]):
Bar()Questo perché, invece di utilizzare un input logic per if per scegliere quale branch selezionare, l'esito positivo delle operazioni contenute nel predicato di if viene utilizzato per decidere il branch appropriato: il branch then se tutte le operazioni riescono, il branch else (se presente) se qualche operazione non riesce. Tieni presente che questo significa che nel predicato if si possono utilizzare operazioni arbitrarie, compresa l'introduzione di costanti. Ad esempio:
Main(X : int) : void =
Y = array{1, 2, 3}
if:
Z0 := Y[X]
Z1 := Y[X + 1]
then:
Use(Z0)
Use(Z1)In altre parole, l'ambito del branch then include qualsiasi nome introdotto nel predicato if.
Comportamento transazionale
Un'altra deviazione di if rispetto ad altri linguaggi di programmazione è il comportamento transazionale del predicato di if. Il predicato di if non deve avere l'effetto no_rollback (utilizzato implicitamente da tutte le funzioni che non specificano esplicitamente transacts, varies o computes). Ciò avviene perché, in caso di errore del predicato, tutte le operazioni eseguite durante l'esecuzione del predicato (ad eccezione di quelle che influiscono su risorse esterne al runtime, come l'I/O di un file o la scrittura sulla console) vengono annullate prima dell'esecuzione del branch else. Ad esempio:
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 funzione Foo(-1) restituirà 0, mentre Foo(1) restituirà 1. Questo perché, sebbene la chiamata a Incr avvenga prima del test di X > 0, la mutazione di Y che provoca viene annullata prima dell'esecuzione del branch else. Tieni presente che Incr ha dovuto specificare manualmente l'effetto transacts. Per impostazione predefinita, il comportamento transazionale non è previsto, indicato dall'effetto implicito no_rollback, ma può essere aggiunto specificando manualmente l'effetto transacts (eseguendo l'override dell'effetto implicito no_rollback).