user=> (defn f [^Double x] x)
#'user/f
user=> (defn g [^double x] x)
#'user/g
user=> (f 1.0)
2.15078317008181E-316 # GASP!
user=> (g 1.0)
1.0 # CROWD APPLAUDS!
As you can see, there is a workaround: use ^double, not ^Double. This
matches what you would do in ClojureJVM. Not to say the observed behavior
isn't faulty and needs fixing.
This workaround is not possible for your extend-protocol example. However,
making System.Double work as you expect for primitive type hinting on fn
arguments should also fix the extend-protocol problem.
Probably over this weekend.
--------
If you care to understand more fully:
The problem stems from the difference in how primitives are handled in the
JVM vs the CLR. Sparing the details, it surfaces here in the fact that
java.lang.Double and System.Double are significantly different.
java.lang.Double is a (primitive) wrapper type,. There is no equivalent in
CLR; certainly a double can be boxed, but that is not the same.
Said another way:
In Java void f(double x) { ... } is not the same as void f (Double x) {
... }.
In C#, void f(double x) {...} is the same as void f (Double x) { ... }.
Said yet another way
In JAVA: double.class != Double.class
in C#: typeof(double) == typeof(Double)
The distinction in the JVM is the reason ClojureJVM asks you to use the
symbols double, float, int, etc. for type-hinting primitives.
At the moment, ClojureCLR matches the spec of ClojureJVM for type-hinting
primitives. if you hint with a type, such as System.Double or
System.String, other things happen. These other things match ClojureJVM
mostly -- the problem being when the type is a primitive type such as
System.Double.
I think the only place there is a problem is primitive type hints on
parameters and fn return types. Type hints used to avoid reflection are not
a problem.
Your protocol example has the same root problem. Unfortunately, there is
no simple workaround as with parameter type hints. ClojureJVM has no
equivalent to
(extend-protocol FooProto System.Double (foo [d] d))
because System.Double is not the same critter as java.lang.Double. One can
do
(extend-protocol FooProto java.lang.Double ... )
in ClojureJVM, but
(extend-protocol FooProto double (foo [d] d))
is not possible.
The problem is actually the same under the surface:
(extend-protocol FooProto T (foo [d] d))
expands into something including (foo [^T d) d) and we are back to our
primitive type-hinting problem. So, making primitive type-hinting work
using System.Double should also solve this problem.
I'll work on it. Should be this weekend.
-David
On Thursday, November 29, 2012 11:02:19 AM UTC-6, ffailla wrote:
>
> I have discovered some odd behavior when type-hinting fns with
> ^System.Double:
>
> user=> (defn bar [^System.Double d] d)
> #'user/bar
> user=> (bar 1.2)
> 2.35293190771409E-316
> user=> (bar 1)
> 2.35069794048985E-316
>
> The same behavior occurs when extending double via extend-protocol or
> extend-type:
>
> user=> (defprotocol FooProto (foo [_]))
> user=> (extend-protocol FooProto System.Double (foo [d] d))
> nil
> user=> (foo 1.2)
> 2.25126584588049E-316
>
> Any ideas? Thanks.
>
> -Frank Failla
>
>
--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to [email protected]
Note that posts from new members are moderated - please be patient with your
first post.
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en