Scoping
Identifiers in Shim can be referenced within the block they are defined and any blocks nested inside that block.
{
let x = 3
print(x)
{
print(x)
let y = 4
print(y)
}
print(y) // <--- This will fail since `let y = 4` is inside the nested block
}Press the play button to execute
Importantly, the variables do not need to have a unique name inside a nested block.
Instead, if a variable is declared with let x = ... inside the block it means
that the x variable outside of the block won’t be changed.
let x = 3
print("x:", x)
{
let x = x
x += 1
print("x:", x)
x += 1
print("x:", x)
x += 1
print("x:", x)
}
// This refers to the `x` from the top of the snippet, which should be unchanged
print("x:", x)Press the play button to execute
Functions declared in the same block are able to call each other. The only thing is that a function needs to have been declared before it can be called.
fn func_a(count) {
if count < 0 {
return
}
print(count)
count -= 1
func_b(count)
}
// NOTE: We can't call `func_a` here since it needs to call `func_b` which is not defined
fn func_b(count) {
print(count)
count -= 1
func_a(count)
}
func_a(5)Press the play button to execute
Advanced Scoping
Scoping comes into greater focus when you look at closures.
fn get_funcs() {
let x = 13;
fn ret_x1() {
x
}
// This closure will capture the new `x`. The `let` that shadows the original
// `x` is treated as a completely distinct location for values to be stored.
let x = 42
fn ret_x2() {
x
}
(ret_x1, ret_x2)
}
let (a, b) = get_funcs()
print(a())
print(b())
assert(a() == 13) // Bug in runtime
assert(b() == 42)Press the play button to execute
NOTE: The runtime has a bug here. Closures referencing shadowed variables don’t reference the original. This should be fixed when bytecode generation is updated to reference locals by id rather than by name.