Scope of a variable determines where a variable exists and its lifetime indicates how long it lives. A variable declared at the top level generally lives till the end of the program.
var name = "Kal". ;; top-level scope, lives forever
scope.kal
Symbols
{
and
}
start a scope.
Anything declared within a scope is tied to it and hence lives as long as the scope lives.
Inner scopes can access and modify all valid variables from the outer scope.
;; outer scope
var name = "Kal".
if 1 + 1 == 2 {
;; new scope
var pi = 3.14.
stdout pi "\n". ;; accessible here
stdout name "\n" ;; accessible here
}
stdout name "\n". ;; accessible here
stdout pi "\n". ;; inaccessible here / error
scope.kal
Once the scope ends, the Garbage Collector will clean up all the variables local to that scope.
if
,
elif
,
else
,
loop
and function (
fn
) bodies all are scoped.
If you intend for some data to be short lived, you can place it in an empty scope.
Empty scopes allow you to set up custom scopes without needing context of
if
,
loop
and other bodies.
var name = "Kal".
{
;; empty scope
var pi = 3.14.
stdout pi "\n".
}
;; inaccessible here / err
stdout pi "\n".
emptyScope.kal
In certain scenarios, you may want to declare a variable inside a scope, but not keep it tied to its lifetime.
Static variables are allowed to live freely outside their tied scope and are cleaned up by the garbage collector once the program ends.
fn testStatic -> {
var x = 10. ;; tied to testStatic
static y = 10. ;; exists freely
x = x + 5.
y = y + 5.
stdout "X: " x " Y: " y "\n".
}
;; call testStatic five times
:testStatic.
:testStatic.
:testStatic.
:testStatic.
:testStatic.
;; accessible even outside testStatic
stdout "\nY = " y "\n". staticVariables.kal
Let's understand what happened here:
Variable
x
is defined and is local to the
testStatic
function. Variable
y
is defined in the same function but its lifetime is not tied to
testStatic
's scope.
When
testStatic
is called once,
x
is created, assigned 10, incremented by 5 resulting in 15 and displayed. The function ends and so does
x
.
y
on the other hand is not garbage collected since it's free from the function's scope.
On the next function invocation,
x
is created and destroyed with 15 being the final value.
However,
y
is incremented by its previous value resulting in 20.
This happens for the rest of the invocation leaving
y
with 35 as the final value.
Since
y
is a static variable, it can be accessed outside the function body.
But what happens when you re-declare a variable in an inner scope that's already declared in the outer scope?
This is where Variable Shadowing comes into action.
Two variables can have the same names as long as they are in different scopes, whether it be an entire separate scope or a nested inner scope.
While in the inner scope the variable assumes its latest assigned value. Once the scope ends, it reverts to its original value.
;; original value
var name = "Earth".
if 1 + 1 == 2 {
;; `name` shadowed
var name = "World".
;; shadowed value used
stdout "Hello " name "!\n".
}
;; original value used
stdout "Hello " name "!\n".
shadow.kal