# Variables
In Ride, you can only declare a variable along with a value assignment. The =
sign must be followed by an expression. The value of the variable is the expression result.
Ride variables are immutable: the value of a variable cannot be changed after it is defined.
Ride is strongly typed and the variable's type is inferred from the value.
# Lazy Variables
let
keyword defines a variable with lazy evaluation: the variable is not evaluated immediately, but only the first time the variable is used.
Examples:
let a = 42 # Integer variable definition
let b = "Ride the Waves!" # String variable definition
You can define variables globally, inside any function, or even inside a variable definition.
func lazyIsGood() = {
let c = {
let d = 1
true
}
c
}
The function above returns true
, but variable d
won't be evaluated because unused lazy variables are not evaluated.
Note that lazy variables are evaluated not in the same order they are defined, but in the order they are used.
# don't do this
func foo() = {
...
let balanceBefore = wavesBalance(this).regular
let result = invoke(dApp2,"bar",args,[AttachedPayment(unit,100000000)])
let balanceAfter = wavesBalance(this).regular
if(balanceAfter < balanceBefore) then ... else...
}
In this example, balanceAfter
would be evaluated before balanceBefore
, and their values would be the same. invoke()
won't be called at all.
# Strict Variables
strict
keyword defines a variable with strict (eager) evaluation. Unlike lazy variables defined with let
, a strict variable is evaluated immediately when script execution reaches it, that is, before the next expression.
Strict variable can only be defined only inside another definition, for example, inside the body of a function. A strict variable will not be evaluated if it is defined inside another definition that is not used: for example, inside a function that has not been called.
Strict variables are suitable for dApp-to-dApp invocation as they ensure executing callable functions and applying their actions in the right order. Example:
func foo() = {
...
strict balanceBefore = wavesBalance(this).regular
strict result = invoke(dApp2,"bar",args,[AttachedPayment(unit,100000000)])
strict balanceAfter = wavesBalance(this).regular
if(balanceAfter < balanceBefore) then ... else...
}
This example evaluates balanceBefore
first, then result
with a call to invoke()
, then balanceAfter
. The values of balanceBefore
and balanceAfter
may differ because payments to dApp2
and actions performed by the bar
callable function affect the balance.
Note that using lazy and strict variables together can have unexpected effects. Example:
# don't do this
{-# STDLIB_VERSION 8 #-}
{-# CONTENT_TYPE DAPP #-}
{-# SCRIPT_TYPE ACCOUNT #-}
let lpTokenId = base58'...'
let rewardTokenId = base58'...'
@Callable(i)
func burn(amount: Int) = [ Burn(lpTokenId, amount) ]
@Callable(i)
func reward() = {
let p = value(i.payments[0])
if p.assetId != lpTokenId
then throw("Incorrect payment")
else {
let lpQty = assetInfo(lpTokenId).value().quantity
let rewardQty = assetInfo(rewardTokenId).value().quantity
let share = fraction(p.amount,rewardQty,lpQty)
strict result = invoke(this, "burn", [p.amount], [])
[
ScriptTransfer(i.caller, share, rewardTokenId)
]
}
}
The share
variable is lazy, so the reward()
function first calls the burn()
function and then evaluates share
. For example, if there are 100 LP tokens in total and a user attached 20 of them to the script invocation, then 20 LP tokens are burned first, then the share (20 LP tokens of the remaining 80) is calculated. As a result, the user receive not 20%, but 25% of the total quantity of the reward token.
Strict variables are added in Standard library version 5.
# Built-in Variables
The Standard library defines built-in variables that you can use in scripts.