С помощью выражения if можно принимать решения, которые будут влиять на поток выполнения программы. Как и в других языках программирования, выражение 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 составляет более трёх метров, то условие соблюдается («успех») и перед сбросом высоты падения игрока выполняется функция DealDamage(). В противном случае условие не соблюдается и игрок не получает урон; при этом значение высоты падения игрока все равно сбрасывается.
if
В примере с высотой падения игрока используется следующий синтаксис:
expression0
if (test-arg-block):
expression1
expression2После выполнения expression0 поток выполнения программы Verse входит в блок if. Если условие test-arg-block соблюдается, то программа Verse выполняет expression1, в качестве которого может выступать как отдельное выражение, так и блок выражений. В противном случае, если условие test-arg-block не соблюдается, то программа Verse пропускает выполнение блока expression1 и сразу переходит к expression2.
Диаграмма логики блока if.
if … else
Вы также можете указать выражение, которое будет выполняться при несоблюдении условия if.
К примеру, игрок должен получить способность двойного прыжка, если он падает менее чем с трёх метров и значение его счётчика прыжка составляет 100 процентов. Но если он падает более чем с трёх метров или значение счётчика прыжка составляет менее 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 менее трёх метров, а также равно ли JumpMeter 100 процентам. Если условие соблюдается, то перед выполнением функции SetDoubleJumpCooldown() выполняются функции ActivateDoubleJump() и ZeroPlayerFallHeight().
Если условие if не соблюдается, то перед SetDoubleJumpCooldown() выполняется функция ActivateFlapArmsAnimation() из блока else.
Синтаксис выражения if-else выглядит следующим образом:
expression0
if (test-arg-block):
expression1
else:
expression2
expression3Диаграмма логики блока if-else.
if … else if … else
Если щит игрока при падении с более чем трёх метров составляет 100 процентов, то игрок должен получить максимальный урон, но при этом выжить. Изменим правило, дающее игрокам способность двойного прыжка, таким образом, чтобы игроки получали данную способность только при падении с менее чем трёх метров и если значение счётчика прыжка составляет более 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
expression4Диаграмма логики блока if-else if-else.
if … then
Вы также можете записать любое из условий if из предыдущих примеров в несколько строк, не нарушив его работу:
expression0
if:
test-arg-block
then:
expression1
expression2Блок test-arg-block может содержать одну или несколько строк условий, однако для выполнения expression1 перед expression2 все они должны соблюдаться, в противном случае будет выполнено только 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 может быть записан в виде однострочного выражения, аналогично тернарным операторам в других языках программирования. К примеру, если вы хотите присвоить максимальное или минимальное значение Recharge в зависимости от уровня щита игрока ShieldLevel, то на языке Verse это можно сделать следующим образом:
Recharge : int = if(ShieldLevel < 50) then GetMaxRecharge() else GetMinRecharge()Требования к предикатам
Предикат в выражении if, представляющий собой выражение в круглых скобках (), в отличие от других языков программирования не должен возвращать булево значение (logic в языке Verse). Вместо этого предикат должен иметь эффект decides (заметим, что несмотря на то что подтипирование обычно позволяет использовать подмножество эффектов там, где допускается набор эффектов, необходимо, чтобы общий эффект предиката включал decides). Эффект исключается из окружающей области видимости. То есть эффект decides в результате всех операций в предикате if в определённом смысле «поглощается» конструкцией if. К примеру, в коде, приведённом ниже, у Main отсутствует эффект decides, однако при этом Main вызывает метод Foo, у которого данный эффект имеется.
Foo()<transacts><decides> : void = {}
Bar() : void = {}
Main() : void =
if (Foo[]):
Bar()Вместо того чтобы использовать для выбора ветви входные данные типа logic выражения if, именно «успешность» выполнения операций в предикате 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). Если выполнение предиката окажется неудачным (с ошибкой), то все операции, произведённые во время его выполнения (за исключением любых операций, влияющих на ресурсы вне среды выполнения, таких как ввод/вывод файлов или запись в консоль), перед выполнением ветви 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. Это происходит потому, что, несмотря на то что вызов функции Incr происходит до проверки условия X > 0, соответствующее изменение значения Y перед выполнением ветви else будет отменено. Также важно отметить, что для функции Incr необходимо вручную указать эффект transacts. По умолчанию транзакционное поведение не предусмотрено, на что указывает неявный эффект no_rollback, но такое поведение можно задать, указав эффект transacts вручную (и переопределив тем самым неявный эффект no_rollback).