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

Reply via email to