Profiling
Should verify that this doesn't add significant runtime overhead over manually type hinting, and especially that it is always faster than letting Clojure do runtime reflection.
Performance will vary depending on several factors, such as
- whether we are doing (runtime) coercion
- the number of potentially matching overloads
- the number of function arguments (arity)
- probably other factors
I have made some tests a while back with wrapping a java library with tortilla, type hinting myself and un-type-hinted with reflection.
(println)
(let [n 100000
args [[300 400] 50 100 g/white]]
(println "tortilla")
(time (dotimes [_ n] (apply g/filled-ellipse-tortilla args)))
(println "type hint")
(time (dotimes [_ n] (apply g/filled-ellipse-type-hint args)))
(println "reflection")
(time (dotimes [_ n] (apply g/filled-ellipse-reflection args)))
)
(println)
;tortilla
;"Elapsed time: 2443.44484 msecs"
;type hint
;"Elapsed time: 1280.779603 msecs"
;reflection
;"Elapsed time: 1724.707907 msecs"
Tortilla is slower than not-type-hinted code with reflection.
I would suggest to put a warning on the README because the whole point of this library is to do the type hinting for us.
I was looking at the implementation and wondering why you chose to call helper fns instead of just generating the code with macros. I did not look too deep in the logic though.
I also really do not understand how it can be performant with generating MemberInfo records on each function call?
I found another similar wrapper which does only generate code and no extra function calls. https://github.com/henryw374/cljc.java-time/blob/master/dev/defwrapper.clj
In the meantime I have concluded that mostly wrapper-libraries are not really necessary much when doing smart type-hinting, although I started work on a 'burrito' library which automatically wraps whole java packages and all the classes, but did not really see much point in it anymore.
Thanks for the feedback. Yeah, the MemberInfo was a convenient way to combine all the info about a member function into one place, but in hindsight was not a great choice from a performance perspective. I think it would be nice if there was way to do something like this in a clean and performant way, but it would be tricky to do well, and I don't have the time to work on it at the moment. I will add a warning to the README as you suggest.