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