if / else)if statements execute a block of code if a condition is true. The block is closed with the
end keyword. The else branch is optional.
import console from "std/console.vv"
if x == 10
console.print("Ten")
else
console.print("Not ten")
end
Chained conditions are supported using else if. Multiple conditions can be checked in
sequence, and only the first branch that evaluates to true will be executed.
if x == 1
console.print("one")
else if x == 2
console.print("two")
else
console.print("many")
end
begin...end)A begin...end block groups multiple statements into a single unit. It is primarily used to
create a new local scope for variables.
let x = 1
begin
let y = 2
console.print(x + y) // 3
end
// console.print(y) // Error: y is only visible inside the block
while)while loops execute a block of code repeatedly as long as a condition is true. The loop is closed
with the end keyword.
import console from "std/console.vv"
let i = 0
while i < 5
console.print(i)
i = i + 1
end
break, continue)Inside a loop, you can use break to exit the loop entirely, or continue to skip to the
next iteration.
let i = 0
while i < 10
if i == 5
break // Stop at 5
end
i = i + 1
end
try)vv utilizes the std/result.vv module and a prefix try keyword for error
handling. The try keyword evaluates an expression returning a
result record with a type field.
{ type = "ok", value = ... }, the try keyword unwraps the result
and evaluates to the inner value.{ type = "error", value = ... }, the try keyword automatically
triggers an early return from the current enclosing function, propagating the error record upward to the
caller.import result from "std/result.vv"
import console from "std/console.vv"
fun divide(a, b)
if b == 0
return result.error("division by zero")
end
return result.ok(a / b)
end
fun calculate()
// If divide fails, calculate() immediately returns the error.
// If divide succeeds, val gets the unwrapped result.
let val = try divide(10, 2)
console.print(val) // Prints: 5
return result.ok(val)
end
try at Top-Level)If an error is propagated via try and reaches the top-level of a module (outside of any function),
the interpreter will stop execution and print the error content to the standard output.
import result from "std/result.vv"
fun f()
return result.error("something went wrong")
end
fun g()
// The try keyword here triggers an early return from g()
// and propagates the error from f() up to g's caller.
let val = try f()
return result.ok(val)
end
// try g() at the top level will cause the program to exit
// and print: "unhandled error: something went wrong"
try g()
defer)The defer statement schedules a statement to be executed just before the current scope (block,
function, or module) exits.
This is extremely useful for ensuring that resources are cleaned up properly, regardless of whether the scope
exits normally or via a return statement.
The execution order of multiple defer statements is "last defer, first executed".
Because defer supports statements, you can use try to propagate errors from cleanup
code, or just call functions directly to ignore their return values:
import file from "std/fs/file.vv"
let f = try file.create("temp.txt")
// close() return value is silently discarded since we're cleaning up
defer file.close(f)
import console from "std/console.vv"
let process_file = fun()
console.print("Opening file...")
defer console.print("Closing file...")
console.print("Processing file contents...")
end
Output of the above function will be:
Opening file... Processing file contents... Closing file...
When used inside a loop, defer executes at the end of each iteration of the loop, not
when the entire loop finishes. This is useful for cleaning up resources created within a single loop cycle.
import console from "std/console.vv"
let i = 0
while i < 3
defer console.print("End of iteration {i}")
console.print("Start of iteration {i}")
i += 1
end
Output:
Start of iteration 0 End of iteration 0 Start of iteration 1 End of iteration 1 Start of iteration 2 End of iteration 2