Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why do int arrays bound with 'def' accept Long values in Clojure?

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:
like image 513
johncowie Avatar asked Jul 23 '17 21:07

johncowie


1 Answers

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.

like image 185
Sam Estep Avatar answered Sep 18 '22 12:09

Sam Estep