Welcome! Please see the About page for a little more info on how this works.

0 votes
in ClojureScript by

When building a custom comparator function in CLJS I encountered some IMO strange behaviour:

When using the > (or similar) function with two strings directly in the REPL I get an :invalid-arithmetic warning and nil is returned (somewhat similar to CLJ that raises an exception). When I do the same inside a function it will return a boolean with no warning at all (CLJ raises an exception)

CLJS:

clj꞉user꞉> (> "A" "Z")
nil
; ------ WARNING - :invalid-arithmetic -------------------------------------------
;  Resource: <eval>:1:1
 cljs.core/>, all arguments must be numbers, got [string string] instead
--------------------------------------------------------------------------------

clj꞉user꞉> ((fn [x y] (> x y)) "A" "Z")
false

CLJ:

user=> (> "A" "Z")
Execution error (ClassCastException) at user/eval3 (REPL:1).
class java.lang.String cannot be cast to class java.lang.Number (java.lang.String and java.lang.Number are in module java.base of loader 'bootstrap')
user=> ((fn [x y] (> x y)) "A" "Z")
Execution error (ClassCastException) at user/eval5$fn (REPL:1).
class java.lang.String cannot be cast to class java.lang.Number (java.lang.String and java.lang.Number are in module java.base of loader 'bootstrap')

Can anyone explain what is going on?

Thanks,
Julian

1 Answer

+2 votes
by
selected by
 
Best answer

WARNING - :invalid-arithmetic comes from the CLJS analyzer which runs during code compilation. When it can figure out the types of the arguments and that those types aren't numeric, it will issue a warning. When it cannot, like with the function example, it will be silent.

And it doesn't result in a run time error because the underlying platform, JavaScript, allows it. But you still should use ClojureScript's > for it because it's intended to be an arithmetic operation.

In CLJ, the underlying platform, JVM, does not support using > on strings - that's why it's always an error.

by
Thanks for your quick answer Eugene! Makes sense, but does this explain why the evaluated expression `(> "A" "B")`  returns nil? Not that it really matters I think, but it seems inconsistent. I agree only using > etc for numeric types even though it works on the JS runtime.

I
by
I believe that's because using `>` on anything other than numeric types is an undefined behavior. Oh, and in my case it returns expected boolean values in Node-based REPL.
...