Local State
Local state manages temporary variables used within Ursus functions. Unlike contract fields (which persist on the blockchain), local variables exist only during function execution.
What is Local State?
Local state is a type-indexed container that holds temporary values during function execution. It's managed through the UseLocal command.
Key properties:
- Temporary - Exists only during function execution
- Type-safe - All local variables are type-checked
- Scoped - Variables are scoped to their function
- Efficient - No blockchain storage costs
UseLocal Command
The UseLocal command declares which types can be used for local variables in the contract.
Syntax
UseLocal Definition _ := [
type1;
type2;
...
typeN
].
Example
UseLocal Definition _ := [
boolean;
address;
uint256;
string;
(mapping address uint256);
(optional uint256)
].
Important: Include all types you'll use for local variables, including:
- Primitive types
- Composite types (mappings, optionals, arrays)
- User-defined types
Declaring Local Variables
Using var Notation
Syntax:
::// var 'name : type := value .
Examples:
::// var 'balance : uint256 := {1000} .
::// var 'sender : address := msg->sender .
::// var 'active : boolean := @true .
Using new Notation
Syntax:
refine // new 'name : type @ "name" := value ; _ //.
Example:
refine // new 'x : uint256 @ "x" := {42} ; _ //.
Difference:
var- Modern, recommended syntaxnew- Older syntax, allows chaining in one line
Using Local Variables
Reading Variables
Local variables can be used in expressions:
::// var 'x : uint256 := {10} .
::// var 'y : uint256 := {20} .
::// var 'sum : uint256 := x + y .
Modifying Variables
Assign new values to local variables:
::// var 'counter : uint256 := {0} .
::// counter := counter + {1} .
::// counter := counter * {2} .
Scope
Local variables are scoped to their block:
{
::// var 'x : uint256 := {10} .
::// if x > {5} then { ->> } else { ->> } | .
{
::// var 'y : uint256 := x + {5} . (* x is visible *)
::// result := y |.
}
{
::// result := x |. (* x is visible, y is not *)
}
}
Local vs Contract State
| Aspect | Local Variables | Contract Fields |
|---|---|---|
| Lifetime | Function execution | Persistent |
| Storage | Memory | Blockchain |
| Cost | Low | High (gas) |
| Scope | Function-local | Contract-wide |
| Declaration | var / new | Record Contract |
Complete Example
#[translation = on]
#[language = solidity]
Contract Calculator ;
Sends To ;
Types ;
Constants ;
Record Contract := {
last_result: uint256
}.
SetUrsusOptions.
UseLocal Definition _ := [
uint256;
boolean
].
#[pure, returns=_result]
Ursus Definition add (a: uint256) (b: uint256): UExpression uint256 false.
{
::// var 'sum : uint256 := a + b .
::// _result := sum |.
}
return.
Defined.
Sync.
#[returns=_result]
Ursus Definition complex_calc (x: uint256): UExpression uint256 false.
{
::// var 'temp1 : uint256 := x * {2} .
::// var 'temp2 : uint256 := temp1 + {10} .
::// var 'is_large : boolean := temp2 > {100} .
::// if is_large then { ->> } else { ->> } | .
{
::// _result := temp2 |.
}
{
::// _result := {0} |.
}
}
return.
Defined.
Sync.
Advanced Patterns
Temporary Mappings
UseLocal Definition _ := [
(mapping address uint256)
].
Ursus Definition process_balances: UExpression PhantomType false.
{
::// var 'temp_balances : mapping address uint256 := {} .
::// temp_balances[[msg->sender]] := {1000} .
::// var 'bal : uint256 := temp_balances[[msg->sender]] |.
}
return.
Defined.
Temporary Arrays
UseLocal Definition _ := [
(array uint256)
].
Ursus Definition collect_values: UExpression PhantomType false.
{
::// var 'values : array uint256 := [] .
::// values->push({10}) .
::// values->push({20}) .
::// var 'first : uint256 := values[[{0}]] |.
}
return.
Defined.
Temporary Records
Types
Record TempData := {
value: uint256;
flag: boolean
};
UseLocal Definition _ := [
(_ResolveName "TempData")
].
Ursus Definition process_data: UExpression PhantomType false.
{
::// var 'data : TempData := [$ {42} ⇒ value ; @true ⇒ flag $] .
::// var 'v : uint256 := data->value |.
}
return.
Defined.
Best Practices
1. Declare All Used Types
Good:
UseLocal Definition _ := [
uint256;
address;
boolean;
(mapping address uint256)
].
Avoid:
UseLocal Definition _ := [
uint256
].
(* Missing types will cause compilation errors *)
2. Use Meaningful Names
Good:
::// var 'sender_balance : uint256 := balances[[msg->sender]] .
::// var 'is_sufficient : boolean := sender_balance >= amount .
Avoid:
::// var 'x : uint256 := balances[[msg->sender]] .
::// var 'y : boolean := x >= amount .
3. Minimize Local State
Good:
::// var 'balance : uint256 := balances[[msg->sender]] .
::// balances[[msg->sender]] := balance - amount |.
Avoid:
::// var 'temp1 : uint256 := balances[[msg->sender]] .
::// var 'temp2 : uint256 := temp1 .
::// var 'temp3 : uint256 := temp2 - amount .
::// balances[[msg->sender]] := temp3 |.
4. Use Local Variables for Clarity
Good:
::// var 'sender_balance : uint256 := balances[[msg->sender]] .
::// var 'recipient_balance : uint256 := balances[[recipient]] .
::// var 'new_sender_balance : uint256 := sender_balance - amount .
::// var 'new_recipient_balance : uint256 := recipient_balance + amount .
::// balances[[msg->sender]] := new_sender_balance .
::// balances[[recipient]] := new_recipient_balance |.
Avoid:
::// balances[[msg->sender]] := balances[[msg->sender]] - amount .
::// balances[[recipient]] := balances[[recipient]] + amount |.
Common Errors
Missing Type in UseLocal
Error:
Type not found in local state
Solution:
Add the missing type to UseLocal:
UseLocal Definition _ := [
uint256;
address (* Add missing type *)
].
Type Mismatch
Error:
Type mismatch: expected uint256, got boolean
Solution: Ensure variable types match their usage:
::// var 'count : uint256 := {0} . (* Not boolean *)
See Also
- Functions - Using local variables in functions
- Writing Functions - Detailed function guide
- Types and Primitives - Available types
- Quick Start - Complete example with UseLocal