On Nov 6, 8:42 pm, Daniel Spiewak <
djspie...@gmail.com> wrote:
> > So you'd need a runtime instanceof test for Class, and use the
> > fastpath if true, reflection if not.
>
> > Perf could be harder to pin down, as adding an import could cause
> > previously fast code to get slow.
>
> Actually, I was thinking of performing the inference based on *all*
> classes on the classpath, not just the ones which have been imported.
> However, considering the fact that Clojure allows dynamic additions to
> the classpath, coupled with the fact that not all available classes
> need to be loaded, this might not be the best idea.
In my mind, the whole value of this is to leverage the imports. If you
could get fast performance by just importing the classes you know your
code is intending to utilize, without actually having to specify again
at the point of use, there's maximum leverage. Looking at the whole
classpath is definitely too much.
> The idea of call-
> point import scoping is an interesting one, I'm not sure how solid you
> could make it though. I mean, don't you look at the FnExpr types
> prior to analyzing its usage? (at least, that's how I've always
> written my compilers) At the very least, it might make library
> functions a little more interesting (certainly ruling out any pre-
> compilation).
>
> With respect to the separate paths issue, I assume that you're talking
> about something like this:
>
> (defn bad-boy [c x]
> (if c
> (.getMethods x)
> (.length x)))
>
> I think in this case the proper inference would be #{} -- in other
> words, reflection. The overhead of trying to fastpath and then
> fallback in certain branches would probably outweigh any benefits in
> this sort of edge case.
>
I think you missed my point here, which was that the job is not to
determine a single type for x above, but to determine the right method
at each method call. If only class Class has getMethods, then the
inferred type of the first call would be ((Class)x).getMethods,
similarly if only String had length, then the second would be
((String)x).length. There's no need to unify the types. There's
nothing 'bad' about the code above, that's why we're using Lisp - the
type systems are still struggling to be expressive enough. If some
third class had both methods, that would become the preferred branch.
I was not talking about analyzing the contexts of the calls to bad-
boy, or any whole-program analysis.
> > The best you could do is make a type-inferred fastpath, since you
> > could always be wrong
>
> Yeah, that is annoying. I hadn't thought of the fact that you could
> infer at declaration point and get a totally unambiguous type but
> still be wrong (since calls in different scopes could pass unexpected
> types that happen to fulfill the structural signature). How much
> overhead does #getClass() impose these days? I heard they were
> optimizing some of that in Java 6, but I haven't actually benchmarked
> anything. I suppose a simple check of that sort wouldn't ever be more
> expensive that a full-blown reflective call, but still.
>
A type check would be significantly faster than a reflective call, is
a subset of same, and is happening in any case, as the arguments to
all fns are Objects. Even if you found 2 or 3 candidates, making a
multiway branch would be faster.
> At what point are functions actually compiled?
When loaded.
> Is it possible to
> apply some of the techniques used in tracing VMs (e.g. V8) to get some
> improved context before performing the inference? In that case, you
> could actually create several different fast-path compilations
> +fallback. There are just so many complicated places you could go
> with this, it's just a question of implementation details (and of
> course, time to do it).
>
There's no need to go there, IMO. What I've described would be
relatively simple and effective.
Communication with the user about reflection might have to become more
nuanced.
Rich