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 clojure@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+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Reply via email to