Clojure Koans 16 Refs Notebook

Hi! In this notebook I will attempt to break down refs in Clojure into skills, questions, and, perhaps, more.

There are spoilers below for the Clojure Koans.

Original Clojure Koans repository: https://github.com/functional-koans/clojure-koans/

{:deps {org.clojure/clojure {:mvn/version "1.10.1"}
        ;; complient is used for autocompletion
        ;; add your libs here (and restart the runtime to pick up changes)
        compliment/compliment {:mvn/version "0.3.9"}}}
deps.edn
Extensible Data Notation
{:hello (clojure-version)}
0.1s
Clojure

Initial Thoughts

TBD...

(def the-world (ref "hello"))
(def bizarro-world (ref {}))
;; skill 16001: Define the binding of a reference to a symbol (?)
Clojure
;; "In the beginning, there was a word"
(= "hello" (deref the-world))
;; question 16001: What does `ref` stand for in Clojure?
;; answer 16001a: "Refs" (short for "references") are Clojure's way of dealing with immutability.
;; question 16002: What is a reference in Clojure and what does it do specifically?
;; question 16003: How does the `ref` function/macro work in Clojure?
;; question 16004: Is there any differences between a reference binding and a non-reference binding, and if so, what are they?
;; question 16005: What is the word "word" refering to?
;; question 16006: What is dereferencing explained in plain words?
;; skill 16002: Dereference a binding/reference (variable?) by using the `deref` function/macro (?)
Clojure
;; "You can get the word more succinctly, but it's the same"
(= "hello" @the-world)
;; skill 16003: Dereference a binding/reference (variable?) by using the `@` prefix (macro?)
Clojure
;; "You can be the change you wish to see in the world."
(= "better" (do
                (dosync (ref-set the-world "better"))
                @the-world))
;; skill 16004: Update/mutate/replace (?) a reference (?)
;; question 16007: Why is this wrapped in a `dosync` and `do` combo?  
;; skill 16005: Use the `do` macro/function to exercute multiple forms/statements (?) and return the result of the final form/statement (?)
Clojure
;; "Alter where you need not replace"
(= "better!!!" (let [exclamator (fn [x] (str x "!"))]
                   (dosync
                       (alter the-world exclamator)
                       (alter the-world exclamator)
                       (alter the-world exclamator))
                   @the-world))
;; question 16008: What is the difference between `ref-set` and `alter`?
;; question 16009: What is the difference between replacing and altering?
;; skill 16006: Change the value bound to / held by (?) a ref (?) by using `alter`
;; knowledge: Asychronous work such as `ref-set`, `ref`, and `deref` needs to happen within a `dosync` to keep the work within a single "transaction" (?) becuase ... (?)
Clojure
;; "Don't forget to do your work in a transaction!"
(= 0 (do (dosync (ref-set the-world 0))
         @the-world))
;; question 16010: What is a "transaction" in Clojure?
;; answer 16010a: ~~Anytime the value of a reference or object is changed.~~ (?)
;;                Interactions with mutable containers are considered "transactions".
;;                Transactions are `do` blocks where references to mutable state are contained within.
;;  question 16011: What is the role of reification in transactions?
;;  question 16012: Why are transactions (dosync) necessary/helpful?
;;  answer 16012a: Transactions enable/allow "roll-back"
;; 
;;  skill 16007: Create a transaction by using the `dosync` macro/function (?)
;;  question 16013: What does `do` do?
;;  answer 16013a: The `do` makes the evaluation of conatined `do-sync`s eager.
;;  question 16014: What does "eager" mean in the context of transations?
;;  question 16015: What is the difference between "eager" and "lazy"?
;;  answer 16015a: Conceptually speaking, lazy means to evaluate/execute only as needed, versus eager which means to evaluate/execute things as soon as they are encountered.
;;  question 16016: What are concrete, concise examples of "eager" vs "lazy"
;;  question 16017: What is the relevant context of "eager" and "lazy"?
;;  answer 16017a: Data structures can be implemented themselves (intrinsic to the data structure) in an eager or lazy way.
Clojure
;; "Functions passed to alter may depend on the data in the ref"
(= 20 (do
          (dosync (alter the-world #(+ % 20)))))
;; question 16018: My clj-kondo linter tells me that the `do` is redundant. Is this indeed true and if yes why?
;; question 16019: Why might a Clojure programmer prefer `partial + 20` rather than `#(+ % 20)` for the above solution?
;; question 16020: What are the differences between the current solution and this `alter the-world + 20` ?
Clojure
;; "Two worlds are better than one"
(= ["Real Jerry" "Bizarro Jerry"]
   (do
       (dosync
           (ref-set the-world {})
           (alter the-world assoc :jerry "Real Jerry")
           (alter bizarro-world assoc :jerry "Bizarro Jerry")
           [(the-world :jerry) (bizarro-world :jerry)])))
;; question 16021: Why are `[(@the-world :jerry) (@bizarro-world :jerry)]` and the same minus the `@` deref prefixes functionally equivalent here? Or are they not but just appear to be?
;; question 16022: Where and when is it critical to deref?
;; question 16023: What are typical/common gotcha's in Clojure referencing/dereferencing?
;; question 16024: What are some more useful/helpful/clear/concrete examples of `do` and `dosync` used in context?
Clojure

Closing Thoughts

TBD...

2021_05_3 Update:

On the theme of doing better, I'd like to continue to update these notebooks. A list of ideas and to-do's:

  • [ ] Share this and all notebooks in Clojureverse, to facilitate effective collaboration

  • [ ] Review the clojure.org reference on refs (pun not intended)

    • [ ] Update the content in this notebook by answering questions & clarifying skills

  • [ ] Demo some practical use-cases for refs

  • [ ] Get mentor/export level feedback on what are hard requirements vs "sensible" pre-requisites for learning and using refs in Clojure code

Runtimes (1)