Welcome! Please see the About page for a little more info on how this works.

0 votes
in ClojureScript by
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.

2 Answers

0 votes
by

Comment made by: thheller

I forgot setting {{:fn-invoke-direct}} which produces more optimal code but still carries a 3-10% overhead (Chrome, Firefox) so this would still be worth considering IMHO.

Updated benchmark: https://jsbench.me/2qjugq4795/2

0 votes
by
Reference: https://clojure.atlassian.net/browse/CLJS-3071 (reported by thheller)
Welcome to Clojure Q&A, where you can ask questions and receive answers from members of the Clojure community.
...