Search code examples
clojureclojure-java-interop

Mapping a Java native function to an array of char results in exception


So I was trying this:

user=> (Integer/toBinaryString ^int (.charValue \c))
"1100011"
user=> 

And I thought... Well, that looks promising, so let's try this now:

user=> (map #(Integer/toBinaryString ^int (.charValue %)) "some")

ClassCastException java.lang.Character cannot be cast to java.lang.Number  user/eval1209/fn--1210 (form-init3852254868488042860.clj:1)
user=> ; Tried this as well. But without luck:
user=> (map #(Integer/toBinaryString ^int (.charValue %)) (.toCharArray "some"))

ClassCastException java.lang.Character cannot be cast to java.lang.Number  user/eval1249/fn--1250 (form-init3852254868488042860.clj:1)
user=> 

oops! WTF is going on?

I have the thing working after introducing a hack:

user=> (map #(Integer/toBinaryString ^int (.charValue (Character/valueOf %))) "some")
("1110011" "1101111" "1101101" "1100101")
user=> ; Or alternatively:
user=> (map (fn [^Character c] (Integer/toBinaryString ^int (.charValue c))) "some")
("1110011" "1101111" "1101101" "1100101")
user=> ; Or:
user=> (map #(Integer/toBinaryString ^int (.charValue ^Character %)) "some")
("1110011" "1101111" "1101101" "1100101")
user=> 

So, does anyone know why this just won't work without calling Character/valueOf or explicitly casting?


Solution

  • Type hints aren't meant to change a program's semantics. The supposed way to convert a character to a number in Clojure is the int function.

    Example:

    user=> (map #(-> % int Integer/toBinaryString) "some")
    ("1110011" "1101111" "1101101" "1100101")
    

    So to be clear, in Clojure, chars are supposed to always be autoboxed into Characters which aren't numbers. The weird part in your code is therefore not when treating chars as numbers doesn't work, but when it does, because in those cases the type hints change the semantics of your code which they aren't supposed to.