Idiomatic record construction in 1.3

292 views
Skip to first unread message

Alex Miller

unread,
Oct 25, 2011, 9:53:59 PM10/25/11
to Clojure
So I'm catching up with the 1.3 defrecord additions (best docs here
afaik: http://dev.clojure.org/display/design/defrecord+improvements -
will http://clojure.org/datatypes be updated?)

In 1.2, records were constructed only with the positional Java
constructor:
(defrecord Person [first last])
(Person. "alex" "miller")

In 1.3, there are now a plethora of new construction options:
Positional:
p1) (Person. "alex" "miller") ;; "legacy" Java constructor
form
p2) (#user.Person["alex" "miller"]) ;; reader form, ns required
p3) (->Person "alex" "miller") ;; factory function

Map:
m1) (#user.Person{:first "alex" :last "miller"}) ;; reader form, ns
required, default print form
m2) (map->Person {:first "alex" :last "miller"}) ;; factory function
m3) (Person/create {:first "alex" :last "miller"}) ;; static class
factory method

So my question is what my first choice should be when constructing
records and needing positional or map forms? Re positional forms, the
p2 reader form requires the ns so is probably more typing than I'm
likely to do. I'm guessing that p3 is now preferred over p1 as it
hides the interop form. So I'll take p3 as the preferred first
choice.

For maps, m1 is the default form serialization form but requires the
ns, so I doubt I would choose that first. m3 clearly seems designed
for tool usage and does Java interop, so I'm guessing m2 is the likely
preferred first choice.

Thoughts?

Colin Jones

unread,
Oct 25, 2011, 10:24:55 PM10/25/11
to clo...@googlegroups.com
+1

A further argument in favor of your choices is that p3 and m2 both work great with higher-order fns, which I didn't immediately find a way to do with any of the others:

user=> (map (partial apply ->Person) [["bob" "loblaw"] ["stan" "sitwell"]])
(#user.Person{:first "bob", :last "loblaw"} #user.Person{:first "stan", :last "sitwell"})

user=> (map map->Person [{:first "bob" :last "loblaw"} {:last "stan" :first "sitwell"}])
(#user.Person{:first "bob", :last "loblaw"} #user.Person{:first "sitwell", :last "stan"})

Thanks for posting this - I knew there were defrecord changes coming at some point, but didn't realize they were already in in 1.3. Hooray!

-Colin

David Powell

unread,
Oct 26, 2011, 3:02:45 AM10/26/11
to clo...@googlegroups.com

Also, the factory fns are available when you require/use the relevant namespace, so the client doesn't have to use import as well.

--
Dave

Shantanu Kumar

unread,
Oct 26, 2011, 5:10:16 AM10/26/11
to Clojure
Does anybody know if these changes are going to be covered in the
newer Clojure books/editions?

Regards,
Shantanu

Chas Emerick

unread,
Oct 26, 2011, 5:50:12 AM10/26/11
to clo...@googlegroups.com
Certainly are in ours: http://shop.oreilly.com/product/0636920013754.do

I'm sure they're mentioned in Programming Clojure 2ed as well.

- Chas

> --
> You received this message because you are subscribed to the Google
> Groups "Clojure" group.
> To post to this group, send email to clo...@googlegroups.com
> Note that posts from new members are moderated - please be patient with your first post.
> To unsubscribe from this group, send email to
> clojure+u...@googlegroups.com
> For more options, visit this group at
> http://groups.google.com/group/clojure?hl=en

Alex Miller

unread,
Oct 26, 2011, 9:24:23 AM10/26/11
to Clojure
I need to correct that p2 and m1 should not have parens around
them.... sorry about that. Seemed obvious when I read it again this
morning.

The literal reader forms are even trickier in how they treat embedded
expressions. They seem to preserve (and not evaluate) the quoted
forms?

user=> (def p #user.Person[(str "a" "b") "c"])
#'user/p
user=> p
#user.Person{:first (str "a" "b"), :last "c"} ;; note the embedded
str here, not "ab"
user=> (:first p)
(str "a" "b") ;; aroo?

Surely, this is not the intended behavior?


On Oct 25, 8:53 pm, Alex Miller <a...@puredanger.com> wrote:
> So I'm catching up with the 1.3 defrecord additions (best docs here
> afaik:http://dev.clojure.org/display/design/defrecord+improvements-
> willhttp://clojure.org/datatypesbe updated?)

Chouser

unread,
Oct 26, 2011, 9:55:14 AM10/26/11
to clo...@googlegroups.com
On Wed, Oct 26, 2011 at 9:24 AM, Alex Miller <al...@puredanger.com> wrote:
> I need to correct that p2 and m1 should not have parens around
> them.... sorry about that.  Seemed obvious when I read it again this
> morning.
>
> The literal reader forms are even trickier in how they treat embedded
> expressions.  They seem to preserve (and not evaluate) the quoted
> forms?
>
> user=> (def p #user.Person[(str "a" "b") "c"])
> #'user/p
> user=> p
> #user.Person{:first (str "a" "b"), :last "c"}    ;; note the embedded
> str here, not "ab"
> user=> (:first p)
> (str "a" "b")           ;; aroo?
>
> Surely, this is not the intended behavior?

I suspect it is intended. You certainly wouldn't want those interior
forms evaluated at reader time. To be more like literal vectors and
maps, eval would have to know how to handle each record type, find the
forms contained in the values, evaluate them, and build a new record
with the results. Off the top of my head I don't see why this would
be impossible, but it may not be desirable.

--Chouser

Alex Miller

unread,
Oct 26, 2011, 10:32:10 AM10/26/11
to Clojure
I should also mention that the reader form is not record-specific - it
works on any Java object:

user=> #java.util.Date[1319639275929]
#<Date Wed Oct 26 09:27:55 CDT 2011>
user=> #java.lang.String["abcdef"]
"abcdef"
user=> #java.awt.Point[1 2]
#<Point java.awt.Point[x=1,y=2]>

Alex Miller

unread,
Oct 26, 2011, 10:36:07 AM10/26/11
to Clojure
Fogus confirmed it is intended and will reply when he gets a chance.
I'm starting to see why - the values are read as literals and so forms
are read as literals and not evaluated. I expect many people will
find this behavior surprising on first encounter...

Aaron Bedra

unread,
Oct 26, 2011, 10:46:10 AM10/26/11
to clo...@googlegroups.com, Chas Emerick
On 10/26/2011 05:50 AM, Chas Emerick wrote:
> Certainly are in ours: http://shop.oreilly.com/product/0636920013754.do
>
> I'm sure they're mentioned in Programming Clojure 2ed as well.
Yes, they will be in Programming Clojure 2ed

Cheers,

Aaron Bedra
--
Clojure/core
http://clojure.com

Reply all
Reply to author
Forward
0 new messages