Control Flow¶
StxScript provides familiar control flow constructs that compile to Clarity's functional equivalents.
If/Else¶
Conditional branching with if and optional else:
if (balance > amount) {
balance = balance - amount;
} else {
return err(ERR_INSUFFICIENT_BALANCE);
}
Generated Clarity:
(if (> (var-get balance) amount)
(var-set balance (- (var-get balance) amount))
(err ERR_INSUFFICIENT_BALANCE))
In Clarity, if is an expression that always requires both branches. If you omit the else, the compiler generates an appropriate default.
Nested If/Else¶
if (amount == 0u) {
return err(1u);
} else if (amount > MAX_SUPPLY) {
return err(2u);
} else {
return ok(true);
}
Ternary Operator¶
For simple conditional expressions:
Generated Clarity:
Match Expressions¶
Pattern matching on Optional and Response types:
Matching Optionals¶
Generated Clarity:
This is equivalent to Clarity's match on optional values. The some branch binds the inner value to the variable name.
Matching Responses¶
Generated Clarity:
Match in Functions¶
Match is commonly used in read-only functions to handle optional map lookups:
@readonly
function get_balance(account: principal): uint {
match balances.get(account) {
some(balance) => balance,
none => 0u
}
}
Generated Clarity:
For Loops¶
For loops compile to Clarity's fold operation over a generated list. Since Clarity has no unbounded iteration, the loop bounds must be known:
Generated Clarity:
The compiler generates a helper function and a list of the iteration range.
Loop Structure¶
The for loop syntax is:
start: Initial value (must be an integer literal)end: Upper bound (must be deterministic)step: Increment amount
Practical Example¶
@public
function sum_to(limit: uint): Response<uint, uint> {
let total: uint = 0u;
for (let i = 0; i < limit; i = i + 1) {
total = total + i;
}
return ok(total);
}
While Loops¶
While loops also compile to bounded iteration using fold. The compiler generates a bounded fold with a maximum iteration count:
Generated Clarity:
(fold while-helper
(list true true true ... true) ;; bounded iteration list
{ count: (var-get count) })
Bounded Execution¶
Since Clarity does not allow unbounded loops, while loops have a compile-time maximum iteration count. The compiler generates a list of that length for the fold:
Practical Example¶
@public
function find_threshold(target: uint): Response<uint, uint> {
let value: uint = 1u;
while (value < target) {
value = value * 2u;
}
return ok(value);
}
Control Flow in Public Functions¶
Public functions commonly combine control flow with error handling:
@public
function safe_transfer(to: principal, amount: uint): Response<bool, uint> {
// Guard: check amount
if (amount == 0u) {
return err(ERR_INVALID_AMOUNT);
}
// Guard: check balance
let sender_balance = get_balance(tx-sender);
if (sender_balance < amount) {
return err(ERR_INSUFFICIENT_BALANCE);
}
// Perform transfer
balances.set(tx-sender, sender_balance - amount);
balances.set(to, get_balance(to) + amount);
return ok(true);
}
Next Steps¶
- Error Handling - Response and Optional patterns
- Data Structures - Iterating over collections
- Expressions - Conditions and comparisons