Idea: Clojure's defrecord isn't for structs

Maybe this is true, maybe not! What do you think?

Clojure is about maps and keywords. The keywords are namespaced, which allows the maps to be open. This is a crucial difference between modeling in Clojure and modeling in mainstream schools of thought.

History

Please correct if wrong:

Defrecord became a thing in 2010 (Clojure 1.2), it seems, according to this git blame.

If I recall correctly, Datomic (2012) was the first system to push namespaced keywords

Only much later did Rich more heavily encourage attribute namespaces around the time of Spec 1 (2016).

How we got here

What I call the "project.clj problem" demonstrates how we got here. The open nature makes this highly extensible which is why Leiningen is so flexible. But this system is from like 2010 and does not namespace it's data and that makes it frustrating to debug. Did a keyword come out of a compiler, or a build tool, or a build plugin, or a repl? If only there were namespaces, it would be obvious!

How defrecord fits in

Hypothesis:

In a world of open maps and namespaced keywords, the only remaining use case for records is to put protocols on your maps.

For example, if your maps have many keys and there are behaviors like providing default values based on business rules, you need a protocol.

This looks something like:

(defprotocol Browser (pull [this])) (defrecord Context [ident] Browser (pull [this] (->> (::query this) (datascript.parser/parse-query) :qfind :elements (mapcat (comp :value :pattern))))) (-> (Context. :my-foo) (assoc ::query '[:find (pull ?e [:user/name :db/id]) :where [?e]]) (pull)) ;; => (:user/name :db/id)

Note the record does not wrap the map, nor does it enumerate the keys, it simply is the map, plus protocols. If you want to restrict or validate the contents of the map, use clojure.spec.