if 式を使用すると、プログラムのフローを変更する判定を行うことができます。 他のプログラミング言語と同様に、Verse の if 式は条件付き実行をサポートしていますが、Verse では条件で成功と失敗を使用して判定を下します。
たとえば、プレイヤーが落下したときにダメージを受けない高さを定義するコードを作成できます。
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()この例では、PlayerFallHeight が 3 メートルより大きい場合、条件が満たされ、DealDamage() が実行されてから、プレイヤーの落下の高さがリセットされます。 他の場合は、条件が満たされません。プレイヤーはダメージを受けませんが、プレイヤーの落下の高さがリセットされます。
if
プレイヤーの落下の高さサンプルでは、次の構文を使用します。
expression0
if (test-arg-block):
expression1
expression2expression0 を実行した後、Verse プログラムは if ブロックに入ります。 test-arg-block が成功すると、Verse プログラムは expression1 (1 つの式または式のブロック) を実行します。 他の場合は、test-arg-block が失敗して、Verse プログラムは expression1 をスキップして、expression2 のみを実行します。
if ブロック ロジックのフロー チャート
if ... else
if 式が失敗したときに、実行する式も指定できます。
たとえば、プレイヤーの落下が 3 メートル未満であり、ジャンプメーターが 100 パーセントである場合に、ダブルジャンプ能力を獲得するとします。 ただし 3 メートル以上落下、またはジャンプメーターが 100 パーセントではない場合、キャラクターの腕が羽ばたくように動き、プレイヤーにダブルジャンプできないことを知らせます。
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!
この例では、if の条件は、PlayerFallHeight が 3 メートル未満であり、かつ、JumpMeter が 100 パーセントであるかどうかを評価します。 条件が満たされる場合、ActivateDoubleJump() と ZeroPlayerFallHeight() が SetDoubleJumpCooldown() の前に実行されます。
if 条件が満たされない場合、else に続く式 ActivateFlapArmsAnimation() が SetDoubleJumpCooldown() の前に実行されます。
if-else の構文サンプルは次のようになります。
expression0
if (test-arg-block):
expression1
else:
expression2
expression3if-else ブロック ロジックのフロー チャート
if ... else if ... else
プレイヤーが 3 メートルを超えて落下したとき、100 パーセントのシールドがあると、最大のダメージを受けますが、生き延びられます。 そしてダブルジャンプ能力を獲得するルールを変更します。落下が 3 メートル未満であり、ジャンプメーターが 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
if-else if-else の構文サンプルは次のようになります。
expression0
if (test-arg-block0):
expression1
else if (test-arg-block1):
expression2
else:
expression3
expression4if-else if-else ブロック ロジックのフロー チャート
if ... then
前のサンプルで if 条件のいずれも、動作を変えることなく、複数の行に記述することができます。
expression0
if:
test-arg-block
then:
expression1
expression2コードブロック test-arg-block には 1 つまたは複数行の条件を含められますが、expression2 の前に expression1 を実行するためにすべてが成功する必要があります。他の場合は expression2 のみが実行されます。
この形式でサンプルの if ... else セクションを 書き直すと次のようになります。
var PlayerFallHeight : float = CalculatePlayerFallHeight()
if:
PlayerFallHeight < 3.0
JumpMeter = 100
then:
# Perform a double jump.
ActivateDoubleJump()
# Reset the player’s fall height.
ZeroPlayerFallHeight()
単一行の式
他のプログラミング言語にある三項演算子のように、if else を単一行の式として記述できます。 たとえば、プレイヤーの ShieldLevel に基づいて、最大または最小の Recharge 値を割り当てる場合に、次の Verse コードを作成できます。
Recharge : int = if(ShieldLevel < 50) then GetMaxRecharge() else GetMinRecharge()述語の要件
if の述語、つまり丸かっこ () に囲まれた式は、他のプログラミング言語と異なり、ブール値 (Verse の logic) を返すことが想定されていません。 代わりに、述語に decides エフェクトがあることが想定されます (一般にサブタイプ化により、述語の全体エフェクトで decides を含めることが要求される場合、エフェクト セットが許可される場所でエフェクトのサブセットが許可される)。 このエフェクトは取り囲むスコープから除去されます。 つまり、if の述語にあるすべての演算子からの decides エフェクトは、if 構造でなくなります。 たとえば、次のコードでは、Main には decides エフェクトがありませんが、このエフェクトがある Foo を呼び出します。
Foo()<transacts><decides> : void = {}
Bar() : void = {}
Main() : void =
if (Foo[]):
Bar()これは、どのブランチを実行するのかを選択する if に logic 入力を使用するのではなく、if の述語に含まれる演算の成功が適切なブランチを決定するのに使用されます。すべての演算が成功した場合は、then ブランチ、いずれかの演算が失敗した場合は、else ブランチ (存在する場合) になります。 つまり、任意の演算が if の述語で使用できます。定数の導入も可能であることに注意してください。 次に例を示します。
Main(X : int) : void =
Y = array{1, 2, 3}
if:
Z0 := Y[X]
Z1 := Y[X + 1]
then:
Use(Z0)
Use(Z1)言い換えると、then ブランチのスコープには、if 述語に導入された任意の名前を含められます。
トランザクション動作
他のプログラミング言語と比較して、if で異なる点は、if の述語のトランザクション動作です。 if の述語で、no_rollback エフェクトを指定できません (これは明示的に transacts、varies、または computes を指定しないすべての関数で暗示的に使用)。 これは、述語が失敗した場合に、述語の実行時におけるすべての演算 (ファイル I/O やコンソールへの書き込みなど、ランタイムの外部リソースに影響する完了していない処理) が、else ブランチが実行される前に、元に戻されるからです。 次に例を示します。
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)
関数 Foo(-1) は 0 を返し、一方 Foo(1) は 1 を返します。 これは、X > 0 をテストする前に Incr へのコールが起こりますが、それによる Y の変更が、else ブランチの実行前に、元に戻されるからです。 Incr で、transacts エフェクトを手動で指定する必要があったことに注意してください。 デフォルトでは、トランザクション動作は実行されません。暗示的 no_rollback エフェクトが有効です。ただし、transacts エフェクトを指定することで追加できます (暗示的 no_rollback エフェクトをオーバーライド)。