Scoping
Kiwi has two main levels of scope: the global scope of the script, and the local scope of each function call. Blocks such as if and for don’t introduce a scope of their own.
Global variables
Section titled “Global variables”Variables assigned at the top level of a script are global. Functions can read them, and assigning to a global’s name inside a function updates the global.
count = 0
fn increment() count += 1end
increment()increment()println count # 2Local variables
Section titled “Local variables”A variable first assigned inside a function, when no global of that name exists, is local to that call. It disappears when the function returns, and each call gets a fresh one.
fn make_greeting(name) message = "Hello, ${name}" messageend
println make_greeting("Kiwi") # Hello, Kiwifn setup() temp = 1end
setup()println temp # VariableUndefinedError: temp only existed inside setup()Parameters are always local, even when a global has the same name.
Shadowing a global with var
Section titled “Shadowing a global with var”Because plain assignment updates a global of the same name, use var inside a function to declare a local variable that shadows it:
name = "global"
fn rename() var name = "local" nameend
println rename() # localprintln name # globalThis matters most in long scripts where a helper function might reuse a common name such as result or i that also exists at the top level.
Blocks don’t create scope
Section titled “Blocks don’t create scope”if, case, for, while, repeat and try blocks share the scope around them. A variable assigned inside a block is still visible after it, and loop variables keep their last value.
if true status = "ready"endprintln status # ready
for n in [1, 2, 3] do last_seen = nendprintln last_seen # 3println n # 3A variable assigned only in a branch that didn’t run doesn’t exist. When a value is computed in different branches, initialize it first so that it is always defined:
score = 72grade = "F"
if score >= 90 grade = "A"elsif score >= 70 grade = "C"end
println grade # CClosures
Section titled “Closures”A lambda or nested function can use the local variables of the function it was created in, and those variables live as long as the lambda does:
fn make_counter() n = 0 do () n += 1 n endend
tick = make_counter()tick()println tick() # 2A lambda shares a variable it assigns only if the code around it assigned that variable first; otherwise the variable is the lambda’s own, and var always declares the lambda’s own. At the top level this applies to globals too: a lambda written at the top level shares a global only if the script assigned it before the lambda. See Which variables a lambda shares.
Struct instances
Section titled “Struct instances”Inside a struct method, @name refers to an instance variable. Instance variables belong to the object, not to any lexical scope, and each instance has its own. @@name refers to a static variable shared by every instance of the struct. See Structs.
struct Counter static @created = 0
fn new() @value = 0 @@created += 1 end
fn tick() @value += 1 endend
a = Counter.new()b = Counter.new()a.tick()println [a.value, b.value] # [1, 0]println Counter.created # 2Packages
Section titled “Packages”Variables assigned at the top of a package body are package variables, reached from outside as package::NAME. Functions in the same package call each other without the prefix. See Packages.
package settings LEVEL = "debug"
fn describe() "level=${settings::LEVEL}" endend
println settings::LEVEL # debugprintln settings::describe() # level=debug