DEV Community

ivan.gavlik
ivan.gavlik

Posted on

Clojure vars - notes

Intro

  • named references (symbol) to values of fn
  • they live in a namespace
  • mutable reference to an immutable value

Var is separate from the value so you can redefine it

Note: symbol is just name


Dig Deeper

Functions are actually stored in vars

(defn greet [name] (str "hello" name))
; is equal to 
(def greet (fn [name] (str "hello" name)))
; because defn is macro
Enter fullscreen mode Exit fullscreen mode

Dynamic vars

Allows temporary thread-local bindings

(def ^:dynamic *debug* false)

; temporarily change it
(binding [*debug* true]
 (prinlnt *debug*))
Enter fullscreen mode Exit fullscreen mode

Metadata

(def ^{:doc "A counter"} counter 0)
Enter fullscreen mode Exit fullscreen mode

Symbol vs Var

Symbol

Pice of code that names something

(type 'x)
;; => clojure.lang.Symbol
Enter fullscreen mode Exit fullscreen mode

Writen as 'x
Exists in code and data

Var

Runtime object that point to immutable value
Written as #'x or (var x)
Exists at runtime

Symbol ──▶ Var ──▶ Value
x ──▶ #'user/x ──▶ 42

Example explained

(def x 43)
x
; 43
Enter fullscreen mode Exit fullscreen mode

In the code

  1. find the symbol
  2. resolve it to var #'user/x
  3. dereference var
  4. produce 42

Dig Deeper

Note symbol can refere to local binding (not a Var) or local variable

; local binding
(let [x 10]
  x)

; local variable
(fn [x] x) 
Enter fullscreen mode Exit fullscreen mode

Immutability

Vars are mutable
The values they point are (usually immutable)

The var can change what it points to the data/vale cannot change

Imagine a program without vars
we have immutable values but no way to give them names

Vars and namespaces

Namespace is mapping from symbols to vars
Namespace is object that contains vars

(ns math)
; internaly
; pi --> var
; inc --> var
Enter fullscreen mode Exit fullscreen mode

Referring to another namespace

(ns animals)
(def dog "Labrador")

(ns zoo
  (:require [animals]))

animals/dog ;; 


(ns zoo-2
  (:require [animals :as a])) ; aliases

a/dog ; shorthand for animals/dog


(ns zoo-2
  (:require [animals :refer [dog]])) ; refering vars

dog ; shorthland for a/dog
Enter fullscreen mode Exit fullscreen mode

Dereferencing

Var fully qualified name includes namespace: math/pi or user/x

Example

(def x 42)
Enter fullscreen mode Exit fullscreen mode

When evaluating steps

  1. find var
  2. deref var
  3. 42

you can also do dereferencing by:

@#'x 
; or
(deref #'x)
Enter fullscreen mode Exit fullscreen mode

Evaluation pipeline simplify

Examples

(double-it x)
Enter fullscreen mode Exit fullscreen mode
  1. Soruce code contains symbols (double-it x)
    Symbols is name ('x, it has type clojure.lang.Symbol)

  2. Compiler resolve namespace
    What does the symbol x refer to in the current namespace
    So we get namespace-name/x var
    Note: namespace dosen't store values it stores vars

  3. Var is runtime object so it dereferences it to get values

  4. Invocation (of the function or the value)

Why we have vars, what not directly have values, because with vars we have

  • redefintion (REPL)
  • metadata
  • dynaming binding

Dig Deeper

Special Symbols

' — Quote

Dont evaluate this treat it as data

Example

(def x 42)
Enter fullscreen mode Exit fullscreen mode

This means

  1. Resolve symbol
  2. Find the var
  3. Return it value
'x
; => x
Enter fullscreen mode Exit fullscreen mode

This means

  1. Return symbol

#' — Var Quote

Resolve this symbol to its Var

Example

(def x 42)
#'x
;; => #'user/x
Enter fullscreen mode Exit fullscreen mode

The result is not 42
the result is the Var object
To get a value you can dereference it using @

@#'x
;; => 42
; or

(deref #'x)
Enter fullscreen mode Exit fullscreen mode

When to use it

  • Metadata is attached to the Var
  • Testing and mocking
  • Implementing macros
  • Dynamic Vars and advanced runtime features

Top comments (0)