Dynamically creating defrecord

441 views
Skip to first unread message

Sven Richter

unread,
Jan 17, 2015, 12:27:05 PM1/17/15
to clo...@googlegroups.com
Hi,

I am trying to create record definitions dynamically during runtime. What I would like to do is something like this:

(defn mk-rec [record-name namespace arg-list]
  (eval '(do (ns namespace)
           (defrecord record-name arg-list))))

And then call it like this:
(mk-rec "A" "ns" [a b c])
(->ns.A 1 2 3 )

I am trying out different things, but struggle to get it right or find some tutorial for it.

So if anyone is willing to share some working code I'd be really happy.

Thanks,
Sven

Lee Spector

unread,
Jan 17, 2015, 12:45:59 PM1/17/15
to clo...@googlegroups.com
In case it may help I'll paste in below some related code from my Clojush project (https://github.com/lspector/Clojush).

The stuff commented out at the top is how I used to do it with defstruct, which I preferred, but that was a very unpopular perspective. The stuff below is how we do it now with defrecord.

 Best, 

 -Lee

;(defmacro define-push-state-structure []
;  `(defstruct push-state ~@push-types))

;(define-push-state-structure)

;(defn make-push-state
;  "Returns an empty push state."
;  []
;  (struct-map push-state))

;; record-based states (apparently faster)

(defn keyword->symbol [kwd]
 "Returns the symbol obtained by removing the : from a keyword."
 (symbol (name kwd)))

(defmacro define-push-state-record-type []
 `(defrecord ~'PushState [~@(map keyword->symbol push-types)]))

(define-push-state-record-type)

(let [empty-state (map->PushState {})]
  (defn make-push-state
    "Returns an empty push state."
    [] empty-state))

Matching Socks

unread,
Jan 17, 2015, 6:04:53 PM1/17/15
to clo...@googlegroups.com
Did you find something really wrong with defstruct?  Occasions when the basis fields are not known to the programmer seem better met by defstruct than defrecord.  And defstruct has not been deprecated in the API documentation.  The comment "Note: Most uses of StructMaps would now be better served by records"[1] probably refers to times when you know the fields!  Is there really a need to bend over backwards to switch natural defstruct usage over to records?

[1] http://clojure.org/data_structures

James Reeves

unread,
Jan 17, 2015, 7:30:43 PM1/17/15
to clo...@googlegroups.com
On 17 January 2015 at 17:27, Sven Richter <sve...@googlemail.com> wrote:
I am trying to create record definitions dynamically during runtime.

To what end? The right answer depends very much on your end goal.

- James

Christopher Small

unread,
Jan 17, 2015, 7:42:30 PM1/17/15
to clo...@googlegroups.com

The reason you can't just call `(mk-rec "A" "ns" [a b c])` is that your `mk-rec` is a function, and `a`, `b`, and `c` are undefined. To have them interpretted as symbols, you'd either have to explicitly use `['a 'b 'c]`, or write `mk-rec` as a macro (as Lee points towards).

I was able to get a macro that does _almost_ what you want, but wasn't quite able to get the namespacing right (at least cleanly). If you need some reading on macros, I really enjoyed the Joy of Clojure's presentation. The [Clojure for the Brave and True treatment](http://www.braveclojure.com/writing-macros/) seems good, but glimpsing through I found there were a couple of little idioms/tricks that were missing that would have been nice to see. Still a good place to start though probably.

Chris

Lee Spector

unread,
Jan 17, 2015, 7:49:16 PM1/17/15
to clo...@googlegroups.com

On Jan 17, 2015, at 6:04 PM, Matching Socks <phill...@gmail.com> wrote:

Did you find something really wrong with defstruct?  Occasions when the basis fields are not known to the programmer seem better met by defstruct than defrecord.  And defstruct has not been deprecated in the API documentation.  The comment "Note: Most uses of StructMaps would now be better served by records"[1] probably refers to times when you know the fields!  Is there really a need to bend over backwards to switch natural defstruct usage over to records?

[1] http://clojure.org/data_structures

I had thought that there was something closer to deprecation of defstruct in the documentation, or at least that deprecation was advocated by lots of people when we discussed it there.

And then we did some speed tests in our application, and at least from the tests that we did, it appeared records were indeed faster by an amount that mattered for us.

 -Lee

Sean Corfield

unread,
Jan 17, 2015, 9:34:17 PM1/17/15
to clo...@googlegroups.com
On Jan 17, 2015, at 3:04 PM, Matching Socks <phill...@gmail.com> wrote:
> And defstruct has not been deprecated in the API documentation.

Technically true but when you see comments like these out there it’s reasonable to assume that structs should be avoided:

"We intentionally omit ... struct-maps, which are deprecated"
-- Prismatic Engineering Practices
-- https://github.com/Prismatic/eng-practices/blob/master/clojure/20130926-data-representation.md#data-types

"I consider structs to be effectively deprecated so I don't use them at all."
-- Alex Miller
-- http://stackoverflow.com/questions/4575170/where-should-i-use-defrecord-in-clojure/4576143#4576143

"Incidentally, unless you need to stick to Clojure 1.1, you might want to use 1.2's defrecord in preference to defstruct -- in fact, the latter is deprecated in 1.2."
-- Michał Marczyk
-- http://stackoverflow.com/questions/4288360/clojures-macro-define-a-binding-whose-name-is-composed-from-an-argument/4288738#4288738

Sean Corfield -- (904) 302-SEAN
An Architect's View -- http://corfield.org/

"Perfection is the enemy of the good."
-- Gustave Flaubert, French realist novelist (1821-1880)



Sven Richter

unread,
Jan 19, 2015, 10:02:35 AM1/19/15
to clo...@googlegroups.com
Thank you all for your answers and insights. As it often turns out, I don't need them. Clara rules also exposes other ways to pass data into rules.

Best Regards,
Sven

JUAN ANTONIO Ruz

unread,
Jan 26, 2015, 2:53:43 PM1/26/15
to clo...@googlegroups.com
Hi Sven, 
I was trying to do the same with my library tangrammer/defrecord-wrapper and, just today, I found a couple of links that worked fine for that
Reply all
Reply to author
Forward
0 new messages