Error formatting macro: pagetree: java.lang.NullPointerException

Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Removed references to ^:static, no longer relevant

...

  • 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
  • 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)
  • hint for return goes on arg vector
    • e.g. (defn ^:static foo ^long [x] ...)
    • this so it supports multi-arity with varied returns
  • 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