The problem is not in your code. The problem is in the ClojureCLR compiler's reliance on how the DLR handles calls to methods in these circumstances.
In ClojureCLR, at present: (defn sqrt [x] (Math/Sqrt x)) (sqrt 4.0) # -> 2.0 (sqrt 4) # fails (Math/Sqrt 4.0) # -> 2.0 (Math/Sqrt 4) # -> 2.0 In ClojureJVM, all will succeed. At the highest level, the reason that (sqrt 4) fails in CLR but (Math/ Sqrt 4) succeeds is that the former passes 4 boxed (as in all calls to Clojure functions) and the latter sees the type of the constant and can pass it to Math.Sqrt as an int. For why the CLR and JVM differ, see below. I can make ClojureCLR match ClojureJVM (and probably expectations) or I can make it fast, but it's not clear I can do both. I suspect fealty to ClojureJVM/expectations is more desired. This will take some work as I'll have to figure out the best way to bypass the DLR. In the meantime, a simple workaround: (defn sqrt [x] (Math.Sqrt (double x)) The differences between CLR and JVM in this matter are somewhat grungy. For those who want details, read on. If you have suggestions, ... . Working in C#, think of the following method as a rough approximation to the call to (. System.Math Sqrt x) in your sqrt defn. static double F(object x) { return (double)x; } Namely, it takes an object (because that is what all arguments to Clojure functions get passed in as) and does a conversion (needed for the call to Math.Sqrt). In this case, we do no further work. If you call F(2.0), no problem. If you call F(2), it blows up with an invalid cast. In other words, you can directly cast a boxed double to a double, but you can't directly cast a boxed int to a double. The problem could be solved if there was an easy way to just say UNBOX, but even at the IL level, the UNBOX needs to know the type that is expected. BTW, the corresponding method in Java won't even compile: static double f(Object x) { return (double)x; } The Java way to do this is: static double g(Object x) { return ((Number)x).doubleValue(); } There is no equivalent to the Number type in CLR, so if we want to handle casting boxed ints to double in a general way, we have to go another route: static double G(object x) { return Convert.ToDouble(x); } This does a lot more work than the Java version, I'm guessing. Here is Convert.ToDouble on an object: public static double ToDouble(object value) { if (value != null) { return ((IConvertible) value).ToDouble(null); } return 0.0; } I've written my own approximations to Java's Number.doubleValue, and get performance close to direct casting in some cases, but speed on various arguments is dependent on the ordering of clauses in an if/ elseif construct. Convert.ToDouble will be faster than my code on non- numeric arguments that support IConvertible. Here are some timings of calls (many iterations): argument type (boxed) double int ulong Method Direct cast 229 Convert.ToDouble 442 428 779 MyConvert 244 281 871 -- David On Oct 13, 2:22 am, Dmitry Kakurin <dmitry.kaku...@gmail.com> wrote: > What's wrong with my definition of sqrt? > > user=> (defn sqrt [x] (. System.Math Sqrt x)) > #'user/sqrt > user=> (sqrt 4) > System.InvalidCastException: Specified cast is not valid. > at lambda_method(Closure , Object ) > at AFunction_impl.invoke(Object ) > at lambda_method(Closure ) > at AFunction_impl.invoke() > at REPLCall(Closure ) > > It works from REPL: > user=> (. System.Math Sqrt 4) > 2 > > Notice that > user=> (sqrt 4.0) > 2 > > works as expected. > > - Dmitry --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en -~----------~----~----~----~------~----~------~--~---