Reputation: 3638
Why is there a difference in return types of assoc
and dissoc
in Clojure, when their argument is a record? I mean that assoc
'ing a non-existent key still returns a record, but dissoc
'ing an existing key returns a map.
But, in a sense, both should produce either a map or a record, but not exhibit different behavior. What is the reason for this dissimilarity?
Upvotes: 12
Views: 1392
Reputation: 51500
Record will be converted to an ordinary clojure map only if you'll dissoc
one of its predefined fields. It's very reasonable behavior, because records can't have undefined fields.
Consider the following code:
(defrecord Point [x y])
(def p (Point. 1 2)) ; => Point{:x 1, :y 2}
(assoc p :x 3) ; => Point{:x 3, :y 2}
(dissoc p :x) ; => {:y 2}
(assoc p :z 3) ; => Point{:x 1, :y 2, :z 3}
(dissoc p :z) ; => Point{:x 1, :y 2}
(-> p
(assoc :z 3) ; => Point{:x 1, :y 2, :z 3}
(dissoc :z)) ; => Point{:x 1, :y 2}
As you can see, both assoc
and dissoc
return a record as long as it satisfies Point
definition.
Upvotes: 16
Reputation: 9276
Record instances are guaranteed to include all the fields declared in the record definition.
When a declared field is removed from an instance, this guarantee would be violated. Hence a map is returned.
Apparently they are not guaranteed to exclude all fields not declared in the record definition, thus new fields can be added to instances.
Upvotes: 7