Skip to content

Instantly share code, notes, and snippets.

@rwilson
Created January 9, 2016 02:30
Show Gist options
  • Save rwilson/95b33fdbd503dc3775a0 to your computer and use it in GitHub Desktop.
Save rwilson/95b33fdbd503dc3775a0 to your computer and use it in GitHub Desktop.
Beware dissociating declared record fields
;; tldr; If you treat a record as a map and dissoc a property, clojure converts the
;; record to a PersistentArrayMap under the hood.
;; Example by way of a repl session
user> (defrecord Foo [bar baz]) ;; Define our record type
user.Foo
user> (map->Foo {:bar 1}) ;; Create a Foo...
#user.Foo{:bar 1, :baz nil}
user> (update *1 :bar inc) ;; Modify a Foo...
#user.Foo{:bar 2, :baz nil}
user> (assoc *1 :baz "foobar") ;; it's all still a Foo!
#user.Foo{:bar 2, :baz "foobar"}
user> (.bar *1)
2
;; Ok, let's get wild:
user> (assoc *1 :xyz 123) ;; We can assoc an undeclared property, and remain a Foo.
#user.Foo{:bar 2, :baz "foobar", :xyz 123}
user> (dissoc *1 :xyz) ;; We can dissoc an undeclared property, and remain a Foo.
#user.Foo{:bar 2, :baz "foobar"}
user> (dissoc *1 :baz) ;; But, if we dissoc a declared property...
{:bar 2} ;; ...now it's not a Foo, it's just a map
;; So, if you're doing to dissoc a declared property, be aware that after doing so
;; you will only have a map, which means that the type'd way of accessing declared
;; fields, e.g. `(.bar *1)` is no longer an option.
;; And if you try...
user> (.bar *1)
IllegalArgumentException No matching field found: bar for class clojure.lang.PersistentArrayMap
clojure.lang.Reflector.getInstanceField (Reflector.java:271)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment