Welcome! Please see the About page for a little more info on how this works.

+2 votes
in Records and Types by

Coming from a RDF background I tend to use qualified keywords a lot when defining properties. However after looking at the Reitit HTTP router it appears that defrecord is really benefitial for performance. This often leads me to a choice between performance or clean data representation when designing software.

In order to avoid this dilemma, I think it would be nice if defrecord could support something similar to what is already done for map destructuring

(def m {:domain/id 14 :other/id "UV"})

(let [{:keys [domain/id]} m] id)
;;; ⤷ 14

We could have something like

(defrecord Employee [domain/id domain/full-name]
  Object
  (toString [_]
    (str "<< id: " id ", name: " full-name " >>")))

(def alyssa (->Employee 14 "Alyssa P. Hacker"))

(.toString alyssa)
;;; ⤷ "<< id: 14, name: Alyssa P. Hacker >>"

(:domain/id alyssa)
;;; ⤷ 14

where:

  • the name part is bound in the record definition and is used as the Java internal class field
  • the fully qualified identifier is used when accessing/manipulating the record objects from its map-like interface.
  • collision in the field names would throw

I have implemented a prototype to demonstrate how it could be done in practice. I wonder if such extension has already been considered for clojure.core/defrecord and if there are some design/implementation issues that I am overlooking.

2 Answers

0 votes
by

There are many dimensions to consider for such an idea. Records already have a namespace in one aspect - the namespace of the record type. It seems potentially confusing to have a record type in one namespace with fields that are keys in different namespaces. In any case, I don't think this is something likely to receive attention soon.

0 votes
by

That syntax has the problem that you can't use keywords where the name part is the same. It wouldn't work with every keyword.

I have multiple projects with keywords like :foo/id and :bar/id. When there is an entity that is related to both foo and bar, or if one of them is related to the other, then it's quite normal to have both in the same map. A typical has-a relation in a database.

So this wouldn't work:

(defrecord Example1 [foo/id bar/id])

But if we change it to use the map destructuring syntax, you could give them non-conflicting names to use inside the record. Outside the record the keywords would be used. Like this:

(defrecord Example2 {foo-id :foo/id, bar-id :bar/id})
Welcome to Clojure Q&A, where you can ask questions and receive answers from members of the Clojure community.
...