Bindings (def and var)
Values can be bound to symbols for later use using the keyword
undefined symbols will raise an error.
(def a 100) (def b (+ 1 a)) (def c (+ b b)) (def d (- c 100))
Bindings created with
def have lexical scoping. Additionally, bindings
def are immutable; they cannot be changed after definition.
For mutable bindings, like variables in other programming languages, use the
var keyword. The assignment special form
set can then be used to
update a var.
(def a 100) (var myvar 1) (print myvar) (set myvar 10) (print myvar)
In the global scope, you can use the
:private option on a def or var to
prevent it from being exported to code that imports your current module. You can
also add documentation to a function by passing a string to the
(def mydef :private "This will have private scope. My doc here." 123) (var myvar "docstring here" 321)
Defs and vars (collectively known as bindings) live inside what is called a scope. A scope is simply where the bindings are valid. If a binding is referenced outside of its scope, the compiler will throw an error. Scopes are useful for organizing your bindings and they can expand your programs. There are two main ways to create a scope in Janet.
The first is to use the
do special form.
do executes a series of
statements in a scope and evaluates to the last statement. Bindings created
inside the form do not escape outside of its scope.
(def a :outera) (do (def a 1) (def b 2) (def c 3) (+ a b c)) # -> 6 a # -> :outera b # -> compile error: "unknown symbol \"b\"" c # -> compile error: "unknown symbol \"c\""
Any attempt to reference the bindings from the
do form after it has
finished executing will fail. Also notice that defining
a inside the
do form did not overwrite the original definition of
a for the
The second way to create a scope is to create a closure. The
form also introduces a scope just like the
do special form.
There is another built in macro,
let, that does multiple
once, and then introduces a scope.
let is a wrapper around a combination
dos, and is the most "functional" way of creating
(let [a 1 b 2 c 3] (+ a b c)) # -> 6
The above is equivalent to the example using
def. This is
the preferable form in most cases. That said, using
do with multiple
defs is fine as well.