Currently there is no way to tell the analyzer/compiler to invoke a function directly even if we know that something is a function only, and never IFn/variadic/multi-arity.
(ns test.invoke)
(defn call-me [some-fn arg]
(some-fn arg))
(call-me #(js/console.log %) "foo")
produces
test.invoke.call_me = (function test$invoke$call_me(some_fn,arg){
return (some_fn.cljs$core$IFn$_invoke$arity$1 ? some_fn.cljs$core$IFn$_invoke$arity$1(arg) : some_fn.call(null,arg));
});
test.invoke.call_me((function (p1__91346_SHARP_){
return console.log(p1__91346_SHARP_);
}),"foo");
As you can see there is always the {{some_fn.cljs$core$IFn$_invoke$arity$1}} property test which will always fail and run through {{.call}}. This makes sense for things that may accept {{cljs.core/IFn}} implementations but there are a lot of cases that will only ever receive plain functions (eg. JS interop) and it should be possible to tell that to the compiler via some annotation so it can emit the more optimal {{some_fn(arg)}} code. {{:advanced}} compilation does not take care of this either.
I created a sample benchmark suite here that shows that the prop/call style invoke is consistently slower by 30-40% which I would like to optimize in some rare cases.
See:
https://jsbench.me/2qjugq4795/1
We could either handle this via a the already existing {{^js}} annotation or create something new like {{^fn}}.
(defn call-me [^js some-fn arg]
(some-fn arg))
;; and/or
(defn call-me [^fn some-fn arg]
(some-fn arg))
(defn call-me [some-fn arg]
^fn (some-fn arg))
This is an optimization similar to what {{^not-native}} provides and should be used carefully and sparingly.