Clojure: creating new instance from String class name - constructor

In Clojure, given a class name as a string, I need to create a new instance of the class. In other words, how would I implement new-instance-from-class-name in
(def my-class-name "org.myorg.pkg.Foo")
; calls constructor of org.myorg.pkg.Foo with arguments 1, 2 and 3
(new-instance-from-class-name my-class-name 1 2 3)
I am looking for a solution more elegant than
calling the Java newInstance method on a constructor from the class
using eval, load-string, ...
In practice, I will be using it on classes created using defrecord. So if there is any special syntax for that scenario, I would be quite interested.

There are two good ways to do this. Which is best depends on the specific circumstance.
The first is reflection:
(clojure.lang.Reflector/invokeConstructor
(resolve (symbol "Integer"))
(to-array ["16"]))
That's like calling (new Integer "16") ...include any other ctor arguments you need in the to-array vector. This is easy, but slower at runtime than using new with sufficient type hints.
The second option is as fast as possible, but a bit more complicated, and uses eval:
(defn make-factory [classname & types]
(let [args (map #(with-meta (symbol (str "x" %2)) {:tag %1}) types (range))]
(eval `(fn [~#args] (new ~(symbol classname) ~#args)))))
(def int-factory (make-factory "Integer" 'String))
(int-factory "42")
The key point is to eval code that defines an anonymous function, as make-factory does. This is slow -- slower than the reflection example above, so only do it as infrequently as possible such as once per class. But having done that you have a regular Clojure function that you can store somewhere, in a var like int-factory in this example, or in a hash-map or vector depending on how you'll be using it. Regardless, this factory function will run at full compiled speed, can be inlined by HotSpot, etc. and will always run much faster than the reflection example.
When you're specifically dealing with classes generated by deftype or defrecord, you can skip the type list since those classes always have exactly two ctors each with different arities. This allows something like:
(defn record-factory [recordname]
(let [recordclass ^Class (resolve (symbol recordname))
max-arg-count (apply max (map #(count (.getParameterTypes %))
(.getConstructors recordclass)))
args (map #(symbol (str "x" %)) (range (- max-arg-count 2)))]
(eval `(fn [~#args] (new ~(symbol recordname) ~#args)))))
(defrecord ExampleRecord [a b c])
(def example-record-factory (record-factory "ExampleRecord"))
(example-record-factory "F." "Scott" 'Fitzgerald)

Since 'new' is a special form, I'm not sure there you can do this without a macro. Here is a way to do it using a macro:
user=> (defmacro str-new [s & args] `(new ~(symbol s) ~#args))
#'user/str-new
user=> (str-new "String" "LOL")
"LOL"
Check out Michal's comment on the limitations of this macro.

Here is a technique for extending defrecord to automatically create well-named constructor functions to construct record instances (either new or based on an existing record).
http://david-mcneil.com/post/765563763/enhanced-clojure-records

In Clojure 1.3, defrecord will automatically defn a factory function using the record name with "->" prepended. Similarly, a variant that takes a map will be the record name prepended with "map->".
user=> (defrecord MyRec [a b])
user.MyRec
user=> (->MyRec 1 "one")
#user.MyRec{:a 1, :b "one"}
user=> (map->MyRec {:a 2})
#user.MyRec{:a 2, :b nil}
A macro like this should work to create an instance from the string name of the record type:
(defmacro newbie [recname & args] `(~(symbol (str "->" recname)) ~#args))

Related

Clojurescript `:optimizations :advanced` breaks access to dataset

Following code:
(set! (.. e -target -dataset -some-field) "some-value")
is compiled into:
return a.target.dataset.Qh=Yf(b)
some_field is compressed into Qh. And I need it to be exactly some_field.
I understand this is due to compression optimization. But is there a way to hint, or to bypass this behavior?
PS: simple optimization gives the desired output
return a.target.dataset.some_field=cljs.core.name.call(null,b)}
You may also be interested in the cljs-oops library: https://github.com/binaryage/cljs-oops
Then you can say:
(oset! el "innerHTML" "Hi!")
More examples below, and also on the CLJS Cheatsheet:
The problem is that some-field (or is it some_field or someField?) gets simplified to Qh. This is because the compiler does not know that the dataset object has a some-field property.
One solution is to write extern files so that the Google Closure Compiler will know that the given field must not be renamed.
An other solution is to use aset function or call goog.object.set function. This way you reference the field of the object with a string value and the string values do not get simplified.
Second example:
cljs.user=> (def a (clj->js {"a" 1}))
#'cljs.user/a
cljs.user=> a
#js {:a 1}
cljs.user=> (aset a "b" 2)
2
cljs.user=> a
#js {:a 1, :b 2}

Clojure: create function whose name is given as a parameter at run-time

I'm trying to create a Clojure function, that returns another function with a custom name. My attempts so far:
(defn function-with-custom-name [name] (fn name [] 42))
(function-with-custom-name "hello")
# --> #object[lang.main$function_with_custom_name$name__4660 0xa6afefa "lang.main$function_with_custom_name$name__4660#a6afefa"]
# syntactically ok, but its name is 'name' and not 'hello'
(defn function-with-custom-name [name] (fn (symbol name) [] 42))
# --> CompilerException java.lang.IllegalArgumentException: Parameter declaration symbol should be a vector, compiling:(/tmp/form-init3365336074265515078.clj:1:40)
(defn function-with-custom-name [name] (fn '(symbol name) [] 42))
# --> CompilerException java.lang.IllegalArgumentException: Parameter declaration quote should be a vector, compiling:(/tmp/form-init3365336074265515078.clj:1:40)
I understand that fn is a macro, and therefore proper quoting is probably important for the parameter, but as per above, I could not get it right, but I'm 99% sure there is a way, since (looking at the source of fn), the only criteria is that the first parameter should be recognized as a symbol.
Any hints on how to do this?
EDIT: Use-case, as asked in the comment: I'm writing a simple language interpreter in Clojure, which (among other things) lets you create functions. The functions from my language are currently represented by anonymous Clojure functions. However, it would make debugging the interpreter much easier, if the Clojure functions also did have a name.
EDIT2: The first edit made me think, and I came to the conclusion that I cannot use macro-based solutions for this problem, since I need to create the functions run-time (and, as far as I remember, macros can only work at compile-time). --> Changed the question title for clarity. Still, please don't delete the macro-based answers, since they give helpful insight.
You can use defmacro.
(defmacro function-with-custom-name [name]
`(fn ~(symbol name) ([] 42)))
you can also do it in runtime, without using macros, using namespace functions instead. It can give you the way to register functions from some input for example (i can't really find any good reason for this though, but maybe it's just me)
user> (defn runtime-defn [f-name f]
(intern (ns-name *ns*) (symbol f-name) f))
#'user/runtime-defn
user> (runtime-defn "my-fun" #(* 100 %))
#'user/my-fun
user> (my-fun 123)
;;=> 12300
user> (runtime-defn (read) #(* 200 %))
#input "danger!!!"
#'user/danger!!!
user> (danger!!! 1)
;;=> 200
Update:
For the simple version, you can use defmacro. For a more complicated version (such as used by the potemkin library) you need to mess around with creating a var and "intern-ing" it into the clojure namespace. This is accomplished via clojure.core/intern:
(ns tst.demo.core
(:use demo.core tupelo.test )
(:require [tupelo.core :as t] ))
(t/refer-tupelo)
(defmacro make-fn-macro-unquote [name]
(spyxx name)
`(defn ~name [] 42))
(defn make-fn-func-quote [name2]
(spyxx name2)
(intern 'tst.demo.core (symbol name2) (fn [] 43)))
(dotest
(make-fn-macro-unquote fred)
(spyxx fred)
(is= 42 (spyx (fred)))
(let [wilma-var (make-fn-func-quote "wilma")]
(spyxx wilma-var)
(is= 43 (spyx (wilma-var)))))
Look at the output:
name => clojure.lang.Symbol->fred
fred => tst.demo.core$fn__38817$fred__38818->#object[tst.demo.core$fn__38817$fred__38818 0x5f832a1 "tst.demo.core$fn__38817$fred__38818#5f832a1"]
(fred) => 42
name2 => java.lang.String->"wilma"
wilma-var => clojure.lang.Var->#'tst.demo.core/wilma
(wilma-var) => 43
Note that fred is a clojure function, while wilma-var is a clojure var. Please see this post on the relationship between a symbol like foo and a var and a function.
Note also that the macro version takes an unquoted symbol fred as input, while the function version takes a plain string in double-quotes as input.
So fred is a symbol pointing to a function, while wilma-var is a symbol pointing to a var (which then points to a function). In either case, Clojure allows us to type (fred) or (wilma-var) to make a function call, and we get either 42 or 43 as a result.

How do I get a list of public functions in a ClojureScript namespace?

I want to get a list of public functions from another namespace so they can be exposed as commands.
A similar question for Clojure seemed close, but does not seem to work on ClojureScript.
Another question has answers for Clojurescript, but they either only show how to print them to the REPL, or return all members instead of only the publicly exposed ones.
ClojureScript does not have a resolve function. It is possible to mimic the behavior using hacks, e.g., this one:
(defn ->js [var-name]
(-> var-name
(clojure.string/replace #"/" ".")
(clojure.string/replace #"-" "_")))
(defn invoke [function-name & args]
(let [f (js/eval (->js function-name))]
(apply f args)))
The second question you linked has an answer that refers to the clojure.repl/dir function which prints
a sorted directory of public vars in a namespace.
If you can print them, you can turn them into a string with with-out-str.
Now let's assume we have a namespace called demo.core with one public function called add:
(ns demo.core)
(defn add [a b]
(println "hello from add")
(+ a b))
We can retrieve the public fns from demo.core as strings as follows:
(defn public-fns
"Returns coll of names of public fns in demo.core"
[]
(as-> (with-out-str (clojure.repl/dir demo.core)) public-fns
(clojure.string/split public-fns #"\n")
(map (fn [s] (str "demo.core/" s)) public-fns)))
So with with-out-str we turn them into a list of strings, then split on newline, then prepend the names of public functions with "demo.core".
Then, using our earlier created invoke function, we can obtain add and invoke it with the arguments 1 and 2:
(invoke (first (public-fns)) 1 2)
;; "hello from add"
;; => 3
This is all very hacky, and it might break in advanced compilation, but it works.

Can I refer another namespace and expose its functions as public for the current ns?

I thought use would do it but it seems the mapping created in the current namespace is not public. Here is an example of what I'd like to achieve:
(ns my-ns
(:use [another-ns :only (another-fct)]))
(defn my-fct
[]
(another-fct 123)) ; this works fine
Then I have another namespace like this:
(ns my-ns-2
(:require [my-ns :as my]))
(defn my-fct-2
[]
(my/another-fct 456)) ; this doesn't work
I would like to do that because another-ns is a library to access a database. I would like to isolate all the calls to this library in a single namespace (my-ns), this way all the DB dependent functions would be isolated in a single namespace and it becomes easier to switch to another DB if needed.
Some of the functions of this library are just fine for me but I'd like to augment others. Let's say the read functions are fine but I'd like to augment the write functions with some validation.
The only way I see so far is to hand-code all the mapping into my-ns even for the functions I don't augment.
One way to do this selectively (specifying each function explicitly) is to use something like Zach Tellman's Potemkin library. An example of it's use is found in the lamina.core namespace which serves as the public entry point for Lamina, importing the key public functions from all other internal namespaces.
You can also use clojure.contrib.def/defalias:
(use 'clojure.contrib.def/defalias)
(defalias foo clojure.string/blank?)
(foo "")
Does this help?
(defmacro pull [ns vlist]
`(do ~#(for [i vlist]
`(def ~i ~(symbol (str ns "/" i))))))
Here's an example:
(ns my-ns)
(defmacro pull [ns vlist]
`(do ~#(for [i vlist]
`(def ~i ~(symbol (str ns "/" i))))))
(pull clojure.string (reverse replace))
(defn my-reverse
[]
(reverse "abc"))
(ns my-ns-2)
(defn my-fct-2 []
(list (my-ns/my-reverse)
(my-ns/reverse "abc")))
(my-fct-2)
If you want to just pull in everything, then:
(defmacro pullall [ns]
`(do ~#(for [i (map first (ns-publics ns))]
`(def ~i ~(symbol (str ns "/" i))))))
(pullall clojure.string)
To pull everything from namespace that may have macros defined within use this
(defmacro pullall [ns]
`(do ~#(for [[sym var] (ns-publics ns)]
`(def ~sym ~var))))

How to create default value for function argument in Clojure

I come with this:
(defn string->integer [str & [base]]
(Integer/parseInt str (if (nil? base) 10 base)))
(string->integer "10")
(string->integer "FF" 16)
But it must be a better way to do this.
A function can have multiple signatures if the signatures differ in arity. You can use that to supply default values.
(defn string->integer
([s] (string->integer s 10))
([s base] (Integer/parseInt s base)))
Note that assuming false and nil are both considered non-values, (if (nil? base) 10 base) could be shortened to (if base base 10), or further to (or base 10).
You can also destructure rest arguments as a map since Clojure 1.2 [ref]. This lets you name and provide defaults for function arguments:
(defn string->integer [s & {:keys [base] :or {base 10}}]
(Integer/parseInt s base))
Now you can call
(string->integer "11")
=> 11
or
(string->integer "11" :base 8)
=> 9
You can see this in action here: https://github.com/Raynes/clavatar/blob/master/src/clavatar/core.clj (for example)
This solution is the closer to the spirit of the original solution, but marginally cleaner
(defn string->integer [str & [base]]
(Integer/parseInt str (or base 10)))
A similar pattern which can be handy uses or combined with let
(defn string->integer [str & [base]]
(let [base (or base 10)]
(Integer/parseInt str base)))
While in this case more verbose, it can be useful if you wish to have defaults dependent on other input values. For example, consider the following function:
(defn exemplar [a & [b c]]
(let [b (or b 5)
c (or c (* 7 b))]
;; or whatever yer actual code might be...
(println a b c)))
(exemplar 3) => 3 5 35
This approach can easily be extended to work with named arguments (as in M. Gilliar's solution) as well:
(defn exemplar [a & {:keys [b c]}]
(let [b (or b 5)
c (or c (* 7 b))]
(println a b c)))
Or using even more of a fusion:
(defn exemplar [a & {:keys [b c] :or {b 5}}]
(let [c (or c (* 7 b))]
(println a b c)))
There is another approach you might want to consider: partial functions. These are arguably a more "functional" and more flexible way to specify default values for functions.
Start by creating (if necessary) a function that has the parameter(s) that you want to provide as default(s) as the leading parameter(s):
(defn string->integer [base str]
(Integer/parseInt str base))
This is done because Clojure's version of partial lets you provide the "default" values only in the order they appear in the function definition. Once the parameters have been ordered as desired, you can then create a "default" version of the function using the partial function:
(partial string->integer 10)
In order to make this function callable multiple times you could put it in a var using def:
(def decimal (partial string->integer 10))
(decimal "10")
;10
You could also create a "local default" using let:
(let [hex (partial string->integer 16)]
(* (hex "FF") (hex "AA")))
;43350
The partial function approach has one key advantage over the others: the consumer of the function can still decide what the default value will be rather than the producer of the function without needing to modify the function definition. This is illustrated in the example with hex where I have decided that the default function decimal is not what I want.
Another advantage of this approach is you can assign the default function a different name (decimal, hex, etc) which may be more descriptive and/or a different scope (var, local). The partial function can also be mixed with some of the approaches above if desired:
(defn string->integer
([s] (string->integer s 10))
([base s] (Integer/parseInt s base)))
(def hex (partial string->integer 16))
(Note this is slightly different from Brian's answer as the order of the parameters has been reversed for the reasons given at the top of this response)
You might also look into (fnil) https://clojuredocs.org/clojure.core/fnil
A very similar approach to Matthew's suggestion is to not do the & rest args, but require that callers provide the single extra map argument of flexible (and optional) keys.
(defn string->integer [s {:keys [base] :or {base 10}}]
(Integer/parseInt s base))
(string->integer "11" {:base 8})
=> 9
(string->integer "11" {})
=> 11
There is a benefit to this in that the options are a single argument map and the caller doesn't have to be so careful about passing an even number of extra args. Plus, linters can do better with this style. Editors should also do better with map key-value tabular alignment (if you're into that) than pairs of args per line.
The slight down-side is that when called with no options, an empty map must still be provided.
This is touched on in this Positional Arguments section (Code Smells article).
UPDATE: There is now support in Clojure 1.11 for passing in a map for optional args (using &).