vitvly
vitvly

Reputation: 3638

Assoc and dissoc on Clojure records

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

Answers (2)

Leonid Beschastny
Leonid Beschastny

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

Leon Grapenthin
Leon Grapenthin

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

Related Questions