Clojure Koans 23 Meta Notebook
Original Clojure Koans: https://github.com/functional-koans/clojure-koans/
Spoilers Alert
{: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"}}}
{:hello (clojure-version)}
Initial Thoughts
When and where is using meta beneficial to me as a writer of Clojure?
(def giants
(with-meta Giants
{:league "National League"}))
;; skill 23001: Tag an object with meta data by using the `with-meta` function (?)
;; question 23001: What role & function does `'Giants` play here?
;; question 23002: What is the structure of the object returned by `with-meta`?
;; question 23003: What is meant by "object" in the context of the input for `with-meta`? reference: https://clojuredocs.org/clojure.core/with-meta
;; "Some objects can be tagged using the with-meta function"
(= {:league "National League"} (meta giants))
;; skill 23002: Access an object's meta data by using the `meta` function (?)
;; "Or more succinctly with a reader macro"
(= {:division "West"}
(meta {:division "West"} Giants))
;; question 23004: What role does `Giants` play here? It appears to be a symbol. Might it be a local binding of sorts? Does it function as an object?
;; guess 23004a: It appears that a reader macro for assigning/tagging meta-data to an object is being used to assign a meta-tag hashmap to the symbol `Giants` (?), and then that meta-data is read/accessed by the `meta` function
;; "While others can't"
(= "This doesn't implement the IObj interface"
(try
(with-meta
2
{:prime true})
(catch ClassCastException e
"This doesn't implement the IObj interface")))
;; question 23005: Is the IObj interface a Java thing, a Clojure thing, both, or neither?
;; question 23006: Supposedly, the `with-meta` functon cannot assign meta-data to things (objects?) that do not implement the clojure.lang.IObj interface - What are the things that do not implement clojure.lang.IObj? What are the things that do? How can one programmatically determine if something implements clojure.lang.IObj?
;; "Notice when metadata carries over"
(= {:foo :bar} (meta (merge {:foo :bar} {:a 1 :b 2}
{:b 3 :c 4})))
;; question 23007: What exactly is happening here? What is meant by "carries over"?
;; question 23008: To what is the meta-data here being assigned?
;; "And when it doesn't"
(= nil (meta (merge {:a 1 :b 2}
{:foo :bar} {:b 3 :c 4})))
;; question 23009: What exactly is happening here?
;; "Metadata can be used as a type hint to avoid reflection during runtime"
(= \C ((.charAt String % 0) "Cast me"))
;; skill 23003: Use metadata as a type hint to avoid reflection during runtime (?)
;; question 23010: What is a "type hint" in the above context?
;; question 23011: What is "reflection" in Clojure? Please show concise/concrete/clear examples.
;; question 23012: What is "reflection during runtime"? Please show a couple concise/concrete/clear examples.
;; question 23013: How is this different than `(.charAt "Cast me" 0)`?
;; "You can directly update an object's metadata"
(= 8 (let [giants
(with-meta
Giants
{:world-series-titles (atom 7)})]
(swap! (:world-series-titles (meta giants)) inc)
(:world-series-titles (meta giants))))
;; question 23014: What does the `@` (at) sign prefix stand for?
;; "You can also create a new object from another object with metadata"
(= {:league "National League" :park "AT&T Park"}
(meta (vary-meta giants
assoc :park "AT&T Park")))
;; skill 23004: Create a new object from another object with metadata by using the `vary-meta` function
;; "But it won't affect behavior like equality"
(= giants (vary-meta giants dissoc :league))
;; question 23015: What do they mean by "it", and how so will "it" not affect behavior like equality?
;; question 23016: What exactly is happening here, and what kind of issue is this & when does it occur? (human error, syntax, etc., at read, compilation, runtime, etc.)
;; "Or the object's printed representation"
(= (pr-str Giants) (pr-str (vary-meta giants dissoc :league)))
;; question 23017: What does `pr-str` do exactly?
;; question 23017a: It seems to cast/convert to string type with some differences from the `str` function. from the docs: "pr to a string, returning it" source: https://clojuredocs.org/clojure.core/pr-str
;; question 23018: What does the `pr-str` stand for?
;; answer 23018a: Well... `pr` stands for `pr`, from the docs:
;; Prints the object(s) to the output stream that is the current value
;; of *out*. Prints the object(s), separated by spaces if there is
;; more than one. By default, pr and prn print in a way that objects
;; can be read by the reader
;; source: https://clojuredocs.org/clojure.core/pr-str
Closing Thoughts
Reading the docs lately has been more fun for me. It feels less like gibberish, and more like sage wisdom.
For next time:
[ ] Mine docs for skills: https://clojuredocs.org/clojure.core/pr-str
[ ] Demo turning data into a string: https://clojuredocs.org/clojure.core/pr-str#example-542692cbc026201cdc326c20
[ ] Demo turning string into data: https://clojuredocs.org/clojure.core/pr-str#example-542692cbc026201cdc326c20
[ ] Serialize an object to disk: https://clojuredocs.org/clojure.core/pr-str#example-542692d4c026201cdc327033
[ ] Read docs on `pr`: https://clojuredocs.org/clojure.core/pr
[ ] Find workaround to stringify the result of threading lazy sequences with side-effects where you could get undesired doubling: https://clojuredocs.org/clojure.core/pr-str#example-5a5e020ee4b0a08026c48cf7
[ ] Find workaround to stringify lazy sequence results without side-effects where `str` would result in a `clojure.lang.LazySeq` object: https://clojuredocs.org/clojure.core/pr-str#example-5a7a4adee4b0e2d9c35f741f
[ ] Find workaround to global var print-length limit: https://clojuredocs.org/clojure.core/pr-str#example-5ac34d90e4b045c27b7fac30