I've been perusing Stu Halloway's beta of "Programming Clojure" and I
came across the following example:

(defn describe-class [c]
  {:name (.getName c)
   :final (java.lang.reflect.Modifier/isFinal (.getModifiers c))})

As demonstrated by the *warn-on-reflection* flag, Clojure is unable to
determine a type for c, therefore all (or rather, almost all) of the
calls made upon it must be handled reflectively.  The performance
"solution" suggested in the book is just to annotate the c parameter
with a type:

(defn describe-class [#^Class c] ...)

This is a perfectly valid solution, but it seems a little ugly to me.
The thought that I had is perhaps the Clojure compiler could actually
infer this type automatically.  Languages like ML and Haskell have
been doing this for decades.  Traditionally, Hindley-Milner isn't
applied to object-oriented languages (or rather, languages which deal
with uncontrolled OO constructs), but from what I understand, most of
the reasoning behind this does not apply to Clojure.  For example,
Clojure doesn't have structural or parametric types because of its
dynamic nature.  There would be no *need* to infer any type parameters
on calls out to Java, so the type system could be treated as nominal.

The algorithm I'm thinking of would be something like this:

* Maintain a multi-map of method and field names to classes (this
could be done incrementally based on what classes the compiler knows
are in scope)
* For each parameter with an unfixed type:
   * Traverse the FnExpr AST and find all Java member access to that
parameter
   * For each access, obtain a set of possible classes from the scope
multi-map
   * At each step, intersect the previous set of possible classes with
the subsequent one (think: a fold)
   * Final set can be optimized by choosing the most-specific type
(eliminating the inheritance case)
   * If the final set has size of 1, then the type has been inferred
and can be used to avoid reflection
   * If the set has size 0, then fallback on reflection
   * If the set has size >1, either fallback on reflection or get more
sophisticated

Improvements on this could be added to the >1 case where the second
pass could look for methods of a given name *and* a specific arity.
Subsequent passes could also incorporate inferred types for the method
parameters.

It's not a complete inference algorithm, but it doesn't have to be.
There's nothing stopping Clojure from falling back on reflection for
unfixed types.  The whole logic behind this dance is to avoid
reflection as much as possible, producing a fairly serious
optimization in Java-interop without requiring those ugly type
annotations.

I briefly looked at implementing this myself, but Clojure's compiler
code is...well, it's a compiler.  :-)  At first glance, I couldn't
even figure out where to place the appropriate hooks to kick off this
process.  A better question though is: has this been tried/considered
before?  What are your overall thoughts with regards to this?
--~--~---------~--~----~------------~-------~--~----~
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
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
-~----------~----~----~----~------~----~------~--~---

Reply via email to