...
- fn is specified by an interface (IFn), taking/returning objects
- fns must still satisfy that interface
- How will callers know about primitive params/return, and how to invoke?
- New :static support
- can we decouple from static?
- Overloading
- we leverage in Java root ops (e.g. Numbers) but don't expose
- even? as an example of something that would have to be primitivized in order to be efficient with all arg types
:static
- defn supports {:static true} metadata
- :static fns can take/return longs and doubles in addition to Objects
- compiler will compile static methods in addition to IFn virtual methods
- When compiling direct invocation of :static fn, compiler will look at var metadata and make call to static method
- Note that because it is not going through the var at runtime, will not see any dynamic modifications to the var
- thus 'static'
- Caller won't see redefs, bindings etc
- Like macros, recompile client code to see changes
- Note that because it is not going through the var at runtime, will not see any dynamic modifications to the var
- The var still contains IFn object for HOFs etc
- and you can get dynamic call by using (#'foo ...)
- New ^:keyword metadata
- turns into ^{:keyword true}
- Metadata stacks - ^:static ^:private foo == ^{:static true :private true} foo
- ^long and ^double hints allowed on args
- other reference type hints allowed as well
- unlike for non-statics, these will be enforced (when invoked statically)
- other reference type hints allowed as well
- hint for return goes on arg vector
- e.g.
(defn ^:static foo ^long [x] ...) - this so it supports multi-arity with varied returns
- e.g.
- Static linking - replaces direct binding
Static linking
- Eliminates the overhead of keeping fns in vars
- Normally not an issue, but for small functions vars have 2 overheads:
- volatile can cause cache miss
- volatile inhibits inlining
- Useful even when not using primitive args/returns
- Known limitations
- static fns can't be closures
- temporary limitation
- static fns can't be protocol call sites
Objective - normalize arithmetic semantics between boxed and primitive numbers
...
| Code Block |
|---|
(defn fib [n]
(if (<= n 1)
1
(+ (fib (dec n)) (fib (- n 2)))))
(time (fib 38))
"Elapsed time: 2973 msecs"
;; hint arg and return
(defn ^:static fib ^long [^long n]
(if (<= n 1)
1
(+ (fib (dec n)) (fib (- n 2)))))
(time (fib 38))
"Elapsed time: 390 msecs"
;Use promoting op' ops for arbitrary precision
(defn fib [n]
(if (<= n 1)
1
(+' (fib (dec' n)) (fib (-' n 2)))))
(time (fib 38))
"Elapsed time: 3092 msecs"
;; double arg/return
(defn ^:static fib ^double [^double n]
(if (<= n 1)
1
(+ (fib (dec n)) (fib (- n 2)))))
(time (fib 38))
"Elapsed time: 944 msecs"
;; double arg/return, double operands
(defn ^:static fib ^double [^double n]
(if (<= n 1.0)
1.0
(+ (fib (dec n)) (fib (- n 2.0)))))
(time (fib 38))
"Elapsed time: 448 msecs"
|
...
| Code Block |
|---|
(set! *warn-on-reflection* false)
(defn fact [n]
(loop [cnt n acc 1]
(if (zero? cnt)
acc
(recur (dec cnt) (* acc cnt)))))
#'user/fact
(set! *warn-on-reflection* true)
(defn fact [n]
(loop [cnt n acc 1]
(if (zero? cnt)
acc
(recur (dec cnt) (* acc cnt)))))
NO_SOURCE_FILE:1738 recur arg for primitive local: acc is not matching primitive, had: Object, needed: long
Auto-boxing loop arg: acc
#'user/fact
;; hinted version, non-promoting
(defn ^:static fact [^long n]
(loop [cnt n acc 1]
(if (zero? cnt)
acc
(recur (dec cnt) (* acc cnt)))))
#'user/fact
;;no warning
(fact 12)
479001600
;; but not auto-promoting
(fact 42)
ArithmeticException integer overflow clojure.lang.Numbers.throwIntOverflow (Numbers.java:1575)
;; non-hinted version *is* general
(set! *warn-on-reflection* false)
(defn fact [n]
(loop [cnt n acc 1]
(if (zero? cnt)
acc
(recur (dec cnt) (* acc cnt)))))
;; caller can just leverage BigInt contagion
(fact 42N)
1405006117752879898543142606244511569936384000000000N
;; or, force promoting operations with prime (') ops
(defn fact [n]
(loop [cnt n acc 1]
(if (zero? cnt)
acc
(recur (dec' cnt) (*' acc cnt)))))
(fact 42)
1405006117752879898543142606244511569936384000000000N
|