I'm trying to implement a function similar to new, but where
the type is not known at compile time -- so I want to evaluate
the first argument.
With the help of Google, I found the approach used in new*
below:
(ns dynamic-new)
(defn new* [type-name-as-symbol & args]
(clojure.lang.Reflector/invokeConstructor
(resolve type-name-as-symbol)
(to-array args)))
In simple situations it works ok:
(ns my-namespace
(:refer dynamic-new))
(defrecord MyRecord [a b c])
(= (new MyRecord 1 2 3)
(new* 'MyRecord 1 2 3)
(new* 'my-namespace.MyRecord 1 2 3))
=> true
(= (new java.util.Date 0 0 1)
(new* 'java.util.Date 0 0 1))
=> true
But there's a problem with unqualified symbols.
Continuing with definitions in my-namespace...
(defn instantiate-qualified []
(new* 'my-namespace.MyRecord 1 2 3))
(defn instantiate-unqualified []
(new* 'MyRecord 1 2 3))
(defn both-funs-same? []
(= (instantiate-qualified)
(instantiate-unqualified)))
(both-funs-same?)
=> true
OK -- no surprises above.
But...
(ns another-namespace)
(try (do (my-namespace/instantiate-unqualified)
"succeeded")
(catch Exception e "failed"))
=> "failed"
In another-namespace, the call of my-namespace/instantiate-unqualified
fails because there is no data type or class named MyRecord in that
namespace.
And...
(ns a-namespace-with-a-different-MyRecord)
(defrecord MyRecord [a b c]) ; two MyRecords in different
namespaces
(my-namespace/instantiate-unqualified)
=> #:a-namespace-with-a-different-MyRecord.MyRecord{:a 1, :b 2, :c
3}
So, the function my-namespace/instantiate-unqualified has created
an instance of a-namespace-with-a-different-MyRecord.MyRecord.
This could be a source of confusing bugs.
Now my questions:
Q1. Is this basically the right approach, or is there some other
way to implement new*?
Q2. I can use syntax-quote to qualify a symbol at read time:
(defn instantiate-unqualified []
(new* `MyRecord 1 2 3))
Is that the right way to go?
Q3. It might be a good idea to check in new* that the symbol passed
to it is qualified. In combination with the use of syntax-quote,
this might be a good solution. Is there a way to check for this?
(Perhaps checking whether the symbol's name contains a "."? But
(a) that's slow and (b) I'm not sure it's good enough.)
I had thought that I might be able to use the namespace function
to check this, because
(namespace 'my-namespace/foo) => "my-namespace"
but unfortunately
(namespace 'my-namespace.MyRecord) => nil
Q4. Given that symbols containing "." are qualified, is
(namespace 'my-namespace.MyRecord) => nil
correct behaviour?
(I think I don't fully understand symbols containing "." but
not "/".)
Q5. I've seen the phrase "fully-qualified symbol" used in a few
places. Does this simply mean "qualified symbol"? If there
is such a thing as a partially-qualified symbol, checking
that a symbol is qualified may not help.
Simon
--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to [email protected]
Note that posts from new members are moderated - please be patient with your
first post.
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en