Bindings and Scope
Bindings
A binding is a named value. Create a binding using var.
var speed = 9 var time = 0.4
After a binding is created, you can use it by name in expressions.
var distance = speed * time
To update an existing binding to a new value, leave out the var and assign to it using =.
var y = 0 var height = 17 draw at(0, y, @width, height, fill(red)) y = y + height draw at(0, y, @width, height, fill(black))
Scope
You can only use bindings that are in scope. Once a list of statements ends with a closing brace "}", all the bindings created by those statements are out of scope and no longer visible. In this example, the backgroundColor binding in the if statement is out of scope by the time we try to pass it to fill:
var controlState = #default if controlState == #highlighted { var backgroundColor = red } // This doesn't work because backgroundColor is out of scope. draw fill(backgroundColor)
Instead of creating a new backgroundColor binding that will go out of scope, we can create the binding earlier and assign our new value into it.
var controlState = #default var backgroundColor = white if controlState == #highlighted { backgroundColor = red } // Now backgroundColor is still in scope. draw fill(backgroundColor)
If two bindings have the same name, the most recent binding that's in scope will be used:
var x = 1 if true { // This is a new binding. var x = 2 show(x) // 2 x = 3 show(x) // 3 } show(x) // 1
Note that the inner and outer x are two different bindings. When the inner x goes out of scope, the outer x (still with a value of 1) becomes visible again.
Recursive Bindings
This self-referential binding doesn't make sense: you can't use x to define itself.
var x = x + 1
But sometimes you want to define a function which refers to itself:
// triangular can't be used since it's currently being defined. var triangular = function (x) { if x > 0 { return x + triangular(x - 1) } return 0 } show(triangular(10))
function statements create recursive bindings, where the binding can be used in its own definition:
function triangular(x) { if x > 0 { return x + triangular(x - 1) } return 0 } show(triangular(10))
drawable statements also create recursive bindings:
drawable rects { draw fill(black) draw inset(1, fill(white)) if @width > 20 { draw inset(10, rects) } } draw rects
You can assign to a recursive binding just like a normal binding:
function f() { return 1 } f = function () { return 2 } show(f())
Parameter Bindings
Functions create bindings for their parameters inside the function body. You can assign to them just like any other binding:
function f(x) { x = x + 1 return x * 2 } show(f(7))
Captured Bindings
Both functions and drawables capture the values of bindings from the scope where they are created. You can use captured bindings in expressions, but you can't assign to them:
var fillColor = black function assignFillColor() { // Using the captured variable works... show(fillColor) // ...but assigning to it doesn't. fillColor = red } assignFillColor() draw fill(fillColor)
Once a binding is captured, assigning to it doesn't change the captured value:
var x = 1 function f() { return x } x = x + 1 // Shows "2", the current value for x. show(x) // Shows "1", the value for x captured by f. show(f())
There are two more kinds of bindings: dynamic bindings and state variables, which you can read about on their respective pages.