Reputation: 8990
Apparently, you can't call apply with a record constructor:
(defrecord Foo. [id field])
(apply Foo. my-list)
fails at read time because it is not expecting Foo. in that place.
The only obvious workaround I could think of was to add a factory function:
(make-foo [id field] (Foo. id field))
which can be apply'ed of course.
Am I missing anything? I'd expect this from C#/Java but just thought it was a bit disappointing in Clojure...
Upvotes: 9
Views: 2370
Reputation: 5881
The problem is known and there is lots of talk about it on the Clojure mailing list. More support will probably be added in future Clojure versions.
For now you have to use your own functions or use https://github.com/david-mcneil/defrecord2 which supports some features like:
Upvotes: 3
Reputation: 70239
Circling back on this post-1.3....
In Clojure 1.3, defrecord creates two generated constructor functions. Given:
(defrecord Person [first last])
this will create a positional constructor function ->Person
:
(->Person "alex" "miller")
and a map constructor function map->Person
:
(map->Person {:first "string"})
Because this is a map, all keys are optional and take on a nil value in the constructed object.
You should require/use these functions from the ns where you declare the record, but you do not need to import the record class as you would when using the Java class constructor.
More details:
Upvotes: 11
Reputation: 70239
Foo.
is a Java class constructor so it has typical Java interop constraints with how you call it. Creating a constructor function is a common solution (it also means you don't have to import the Foo when in a different namespace).
Upvotes: 6