С помощью выражения if
можно принимать решения, контролирующие выполнение программы. Как и в других языках программирования, выражение if
обеспечивает ветвление. Однако в Verse решения принимаются на основании получения результата в блоке оператора условия.
К примеру, вы можете написать код, задающий высоту, при падении с которой игрок будет получать урон.
var PlayerFallHeight : float = CalculatePlayerFallHeight()
# Игрок получает урон при падении с высоты более 3 метров
if (PlayerFallHeight > 3.0):
DealDamage()
# Сбросить высоту падения игрока
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):
# Выполнить двойной прыжок.
ActivateDoubleJump()
# Сбросить высоту падения игрока.
ZeroPlayerFallHeight()
else:
# Активировать анимацию размахивания руками, чтобы показать игроку,
# что двойной прыжок сейчас совершить нельзя!
ActivateFlapArmsAnimation()
# Задать время перезарядки двойного прыжка, чтобы анимация «размахивания руками»
# не активировалась в неподходящий момент при быстром нажатии клавиши прыжка.
SetDoubleJumpCooldown()
В этом примере условие в блоке 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
# Сбросить высоту падения игрока
ZeroPlayerFallHeight()
Синтаксис выражений 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:
# Выполнить двойной прыжок.
ActivateDoubleJump()
# Сбросить высоту падения игрока.
ZeroPlayerFallHeight()
else:
# Активировать анимацию размахивания руками, чтобы показать игроку,
# что двойной прыжок сейчас совершить нельзя!
ActivateFlapArmsAnimation()
# Задать время перезарядки двойного прыжка, чтобы анимация «размахивания руками»
# не активировалась в неподходящий момент при быстром нажатии клавиши прыжка.
SetDoubleJumpCooldown()
Однострочное выражение
Блок if else
может быть записан в виде однострочного выражения, аналогично тернарным операторам в других языках программирования. К примеру, если вы хотите присвоить максимальное или минимальное значение Recharge
в зависимости от уровня щита игрока ShieldLevel
, то на языке Verse это можно сделать следующим образом:
Recharge : int = if(ShieldLevel < 50) then GetMaxRecharge() else GetMinRecharge()
Требования к предикатам
Предикат в выражении if
, представляющий собой выражение в круглых скобках (), в отличие от других языков программирования не должен возвращать булево значение (logic
в языке Verse). Вместо этого предикат должен иметь эффект decides
. (Заметим, что несмотря на то что подтипирование обычно позволяет использовать подмножество эффектов там, где допускается набор эффектов, в блоках с if необходимо, чтобы общий эффект предиката включал 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)
X > 0
then:
Y.Contents
else:
Y.Contents
Функция Foo(-1)
возвращает значение 0
, а функция Foo(1)
— значение 1
. Это происходит потому, что хотя вызов функции Incr
происходит до проверки условия X > 0
, соответствующее изменение Y
отменяется перед выполнением ветви else
. Также важно отметить, что для функции Incr
был вручную указан эффект transacts
. По умолчанию транзакционное поведение не предусмотрено, на что указывает неявный эффект no_rollback
, но такое поведение можно задать, указав эффект transacts
вручную (отменив тем самым неявный эффект no_rollback
).