I've noticed that if I def
an int array and set an element in the array with a Long, then there are no complaints. However if I bind the int array in a let
block set an element with a Long, then an IllegalArgument exception is thrown. Could someone help me understand why this is?
The code below demonstrates the discrepancy. I tried it in both Clojure 1.8 and the latest beta version of 1.9 and got these results.
(def a (int-array 10))
(aset a 0 Long/MAX_VALUE) ;; sets first element to -1
(let [b (int-array 10)]
(aset b 0 Long/MAX_VALUE)) ;; throws java.lang.IllegalArgumentException: Value out of range for int:
This discrepancy is caused because type inference is occurring in the let
, but not in the def
. You can verify this by using type hints to switch the situation around:
(def ^"[I" a (int-array 10))
(aset a 0 Long/MAX_VALUE)
;; throws java.lang.IllegalArgumentException: Value out of range for int:
(let [^Object b (int-array 10)]
(aset b 0 Long/MAX_VALUE))
;; sets first element to -1
Or, alternatively:
(def a (int-array 10))
(aset ^"[I" a 0 Long/MAX_VALUE)
;; throws java.lang.IllegalArgumentException: Value out of range for int:
(let [b (int-array 10)]
(aset ^Object b 0 Long/MAX_VALUE))
;; sets first element to -1
This is because Clojure inlines calls to aset
when possible, which includes all these cases, but the inlined static method call has many overloads.