So after thinking about Alex and James' respective answers I think the full answer to your question is that no you can't do that for reasons pretty fundamental to the JVM unless you care to constrain the problem domain or qualify your question some more.
Making a new class instance is a three step dance: 1. Get all the class initialization values on the stack 2. Use the new [1] instruction to create an instance 3. use invokeSpecial [2] to call the <init> constructor The Clojure calling convention is logically Object* -> Object except in the case of JVM primitives [3]. Without my strictly tagged Clojure work, all Clojure locals are also Object typed at the byte code level (again unless primitive) and checkCast instructions [4] are used to dynamically check the tagged types. This means that in the general case of a function as such: ```clojure ;; totally doesn't work ;; presuming that new was not special and could accept varargs (defn make-it [class & args] (apply new class args)) ``` the absolute best bytecode one could possibly emit for this expression would be to 1, iterate over all the args (because it's a varargs seq all we know is that they are Objects in a Seq) pushing them onto the stack last to first. 2, get the class from the arguments, cast it to a class (checkCast) and then use java.lang.Class.newInstance() [5] to create an uninitialized instance. Now we have a problem. In order to initialize and use the new instance, we _must_ invoke the appropriate <init> method, which may not accept Object typed arguments. In your own example you had an inline String. Somehow, for instance by using java.lang.Class.getDeclaredConstructors [6] and looking for constructors somehow matching the sequence of arguments (which are of unknown types, all Object) so that we can then invoke it. All we have on hand is an uninitialized (and probably useless) Object, and a heap of argument Objects. We can do no better here at least statically than to use reflection. This gives the answer of "don't even bother trying to wrap new, just use it" given by James and Alex. And frankly I agree. Inline new is the way to preserve and use the most type information, and is syntactically clear to other programmers. If you _really really really_ want to do "better" than inline new and I claim that you really don't, you could use the following code modified from James' suggestion. ```clojure ;; MIT/X11 license disclaimed ;; - may not work, written late with alcohol ;; - no guarantee for any purpose (def maybe-type? (some-fn nil? ;; implicitly Object symbol? ;; primitive types class? ;; a specific Class )) (defn make-ctor-fn* [class & types] {:pre [;; class cannot be nil, we must make something (class? class)]} (let [args (mapv #(let [c (or % Object)] ;; args must have Types (could be prim) too (assert (maybe-type? c)) ;; make a local sym with the tag (with-meta (gensym) {:tag c})) types)] `(fn ~(with-meta args {:tag class}) (new ~class ~@args)))) (def make-ctor-fn (memoize (fn [& args] (eval (apply make-ctor-fn* args))))) ``` which will at least let you cache the dynamically generated constructor fns and avoid repeatedly calling eval although I make no claim of a meaningful performance difference. Issues with this approach include the following: You have to hit the memoize cache on every call (unless you safe your constructor fns to a local since I'm assuming you're truly doing something type dynamic here). Clojure doesn't (and can't, see Object typed calling convention) statically know the type of the result of your dynamic constructor fn so you'll get back an Object. This means that in order to do any method calls or field accesses you'll have to either use reflection or do more crazy cached dynamic fn generation in order to work with the resulting Class instance in a remotely performant fashion. I claim that whatever you're working on probably isn't actually type dynamic enough to require any of this weirdness if you stop and think about it. But it may in which case cached eval of generated fns with tags may be your best bet. This was written with no effort made to profile anything just from my knowledge of the JVM spec, Java standard library and Clojure. YYMV, get a profiler and look at it for yourself. Reid Citations: [1] https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-6.html#jvms-6.5.new [2] https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-6.html#jvms-6.5.invokespecial [3] https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/IFn.java [4] https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-6.html#jvms-6.5.checkcast [5] https://docs.oracle.com/javase/7/docs/api/java/lang/Class.html#newInstance-- [6] http://docs.oracle.com/javase/7/docs/api/java/lang/Class.html#getDeclaredConstructors%28%29 -- 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 --- You received this message because you are subscribed to the Google Groups "Clojure" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.