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
-~----------~----~----~----~------~----~------~--~---

Reply via email to