Have you seen this? http://www.assembla.com/wiki/show/clojure/Enhanced_Primitive_Support
•hint for return goes on arg vector ◦e.g. (defn ^:static foo ^long [x] …) ◦this so it supports multi-arity with varied returns I couldn't find a practical use of doing (defn ^String foo [] ...) what's hinting the fn name good for? The code in 1.3 is actually better than I had anticipated since you get the speed benefits whether or not your arguments are primitives (see Static linking); I thought you'd need two implementations of every calls that takes primitives. You don't mention ^:static and that seems to be required for best performance. :static •defn supports {:static true} metadata •:static fns can take/return longs and doubles in addition to Objects •compiler will compile static methods in addition to IFn virtual methods The metadata isn't there, so I guess some symbol table is involved in compiling static functions, not just the var. user=> (defn fib [n] (if (<= n 1) 1 (+ (fib (dec n)) (fib (- n 2))))) #'user/fib user=> (time (fib 38)) "Elapsed time: 25383.208481 msecs" 63245986 user=> (defn ^:static fib ^long [^long n] (if (<= n 1) 1 (+ (fib (dec n)) (fib (- n 2))))) #'user/fib user=> (meta (var fib)) {:arglists ([n]), :ns #<Namespace user>, :name fib, :static true, :line 149, :file "NO_SOURCE_PATH"} user=> (time (fib 38)) "Elapsed time: 2792.755504 msecs" 63245986 user=> (time (fib 38N)) "Elapsed time: 2777.905013 msecs" 63245986 On May 11, 8:09 am, Chas Emerick <cemer...@snowtide.com> wrote: > (sorry for the prior hiccup, I accidentally sent a draft of my message) > > I've been using 1.3.0 alphas for real work for a little while now, and would > like to raise a couple of issues around type hinting so as to calibrate my > expectations and understanding and/or provoke some discussion about some > inconsistencies I'm seeing. > > Some observations from a REPL interaction first: > > => *clojure-version* > {:major 1, :minor 3, :incremental 0, :qualifier "alpha6"} > => (set! *warn-on-reflection* true) > true > => (defn ^String foo []) > #'user/foo > => (fn [] (String. (foo))) > #<user$eval398$fn__399 user$eval398$fn__399@215b011c> > => (-> #'foo meta :tag) > java.lang.String > > Right, so hinting a var's name works just fine, as in 1.2.x. Things get > wonky when hinting with primitives, though: > > => (defn ^long foo []) > #'user/foo > => (fn [] (Long. (foo))) > #<CompilerException java.lang.IllegalArgumentException: Unable to resolve > classname: clojure.core$long@41f6321, compiling:(NO_SOURCE_PATH:1)> > => (-> #'foo meta :tag) > #<core$long clojure.core$long@41f6321> > > The compilation fails because the var's :tag metadata is a function, > clojure.core/long! Bizarre. I would assume that that's a bug, except that > it appears the intended way to hint _primitive_ returns (but no other > returns?) is on the arg vector, and not the var name: > > => (defn foo ^long []) > #'user/foo > => (fn [] (Long. (foo))) > #<user$eval410$fn__411 user$eval410$fn__411@18287811> > => (-> #'foo meta :tag) > nil > => (meta @#'foo) > nil > > So our compilation succeeds here, but the var's metadata is left :tag-less > (understandably, since the hint is on the arg vector and not the var name), > and the function has no metadata at all (this is surely a bug, but not my > primary focus here). > > My understanding is that the objective in hinting the arg vector is to allow > for variable return hints on functions with multiple arities (which was not > possible in 1.2.x). This is an excellent aim, but it would seem that the > current implementation presents some usage difficulties: > > => (defn foo > (^String []) > (^long [a]) > (^double [a b])) > #'user/foo > => #(String. (foo)) > #<user$eval2241$fn__2242 user$eval2241$fn__2242@25c2cbee> > Reflection warning, NO_SOURCE_PATH:1 - call to java.lang.String ctor can't be > resolved. > => #(Long. (foo)) > #<user$eval2245$fn__2246 user$eval2245$fn__2246@508a8b07> > Reflection warning, NO_SOURCE_PATH:1 - call to java.lang.Long ctor can't be > resolved. > => #(Long. (foo 0)) > #<user$eval2249$fn__2250 user$eval2249$fn__2250@c23c5ff> > => #(Double. (foo 0)) > #<user$eval2260$fn__2261 user$eval2260$fn__2261@35cfee57> > Reflection warning, NO_SOURCE_PATH:1 - call to java.lang.Double ctor can't be > resolved. > => #(Double. (foo 0 0)) > #<user$eval2264$fn__2265 user$eval2264$fn__2265@5d504a84> > > So, we can have variable hinting of fn returns of different arities, but only > for primitive types. This hurts, and should either be "fixed" or produce a > compiler warning. Also, there is no metadata on the var indicating the types > of the different function arities: > > => (meta #'foo) > {:arglists ([] [a] [a b]), :ns #<Namespace user>, :name foo, :line 1, :file > "NO_SOURCE_PATH"} > > Somewhat worse from the standpoint of semantic consistency, hinting the var > with ^String yields good — yet confusing — results: > > => (defn ^String foo > ([]) > (^long [a]) > (^double [a b])) > #'user/foo > => #(Double. (foo 0 0)) > #<user$eval2289$fn__2290 user$eval2289$fn__2290@69996e15> > => #(String. (foo)) > #<user$eval2293$fn__2294 user$eval2293$fn__2294@220860ba> > > And now the var metadata has a :tag, but only for the ^String hint: > > => (meta #'foo) > {:arglists ([] [a] [a b]), :ns #<Namespace user>, :name foo, :line 1, :file > "NO_SOURCE_PATH", :tag java.lang.String} > > I understand that the generated function implements the necessary interfaces > when primitive hints are involved: > > => (supers (class foo)) > #{clojure.lang.IFn$OL java.lang.Object java.lang.Runnable clojure.lang.Fn > clojure.lang.AFn clojure.lang.IObj clojure.lang.IMeta clojure.lang.AFunction > java.util.concurrent.Callable clojure.lang.IFn$OOD java.io.Serializable > java.util.Comparator clojure.lang.IFn} > > Having to touch (:tag (meta var)) as well as dig away at the implemented > interfaces of generated function classes (which I have to assume are strictly > implementation details) seems unnecessarily inconsistent. > > Finally, I'd like to question the current path of supporting hinting of > primitive returns — and primitive returns only — via function arg vectors. > Again, to me, it's a simple point of consistency, this time from a mostly > syntactic perspective; most of the examples below have already been seen > above, but I repeat them so that they're all co-located for easy comparison: > > We hint object returns via the var name: > > (defn ^String foo []) > > But we hint primitive returns via arg vectors: > > (defn foo ^long []) > > Different arities of functions can be hinted, but _only_ with primitive > types, and on arg vectors: > > (defn foo > (^long []) > (^double [a])) > > While a hint added to a function's var "cascades" down to any unhinted > arities of a function: > > (defn ^String foo > ([] "bar") > (^double [a]) > ([a b] :surprise!) > > I wasn't able to find a canonical discussion of the introduction of this > semantic of hinting argument vectors, so a pointer to one (or a new one > here!) would be great. It doesn't make a lot of sense to me — return hints > are related to the function, not the arguments. I thought that perhaps > hinting the arg vector was provided so as to support hinting returns of > anonymous functions, but that doesn't seem to be the case: > > => (def a (fn ^long [])) > #'user/a > => #(Long. (a)) > #<user$eval2390$fn__2391 user$eval2390$fn__2391@3865db85> > Reflection warning, NO_SOURCE_PATH:1 - call to java.lang.Long ctor can't be > resolved. > > From a naive perspective, understanding that perhaps implementation details > and historical considerations are driving the current state of things, I > would expect this to work, and be the most semantically-consistent usage: > > (defn foo > ^String ([] "bar") > ^double ([a] 5.6) > ([a b] :not-hinted-at-all)) > > …with appropriate metadata on #'foo and the function itself indicating the > corresponding arity<=>return types. > > Of course, this isn't how 1.3.0 alphas work now, but unless things are really > locked down, I hope the above is a reasonable starting point for discussing > how to smooth out the inconsistencies that currently exist. > > Cheers, > > - Chas -- 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