7 ms·
I'll do a bulk reply since there's lots of comments here I would reply to. Clojure doesn't need invokedynamic in general because Clojure doesn't really dispatc
by headius 15y ago
I'll do a bulk reply since there's lots of comments here I would reply to.
Clojure doesn't need invokedynamic in general because Clojure doesn't really dispatch dynamically. It's dynamically typed, but calls are made via a known path to a specific function, and only via rebinding can that target change. The general case goes straight through.
In a sense, it's like Clojure is JRuby where all classes only have one method. With only one method, you can always just call straight in, no lookup required, and avoid dynamic lookup.
If Clojure had to deal with dynamically selecting a method based on a target object type, incoming parameter types, and so on, invokedynamic would be more useful. Indeed, Clojure often hacks around such cases by allowing you to specify Java signatures (to avoid reflection) or primitive types (to avoid boxed math). Both cases could be improved without ugly syntax if invokedynamic were used.
So to summarize, Clojure could get benefit out of invokedynamic...if it hadn't already added hacks and syntax to allow opting out of the most-dynamic cases.
In JRuby, we could avoid a lot of dynamic dispatch by allowing type signatures, type declarations, and so on. But that wouldn't be Ruby, and we don't control Ruby. JRuby compares favorably to Clojure without the typing syntax, performance-wise, which is quite acceptable to me. With invokedynamic, JRuby even compares favorably to Java, with the exception of boxed math (which is very hard to optimize in a dynamic language). For equivalent work, JRuby with invokedynamic is within 2x slower than Java, and that will continue to improve as the Hotspot guys optimize invokedynamic.
- swannodette 15y agoWhile I respect your work on JRuby, I think you're not being honest about JRuby performance here nor being fair about Clojure's design decisions - they are not hacks. Clojure supports unboxed math. One big example to why this important - it's possible to implement Clojure's persistent data structures (and new ones) in Clojure itself. They are the very cornerstone of what Clojure is all about and this is a case where unboxed performance makes all the difference in the world. Persistent data structures are not that relevant to JRuby and thus you don't need to make that design decision.
- headius 15y agoFor a dynamic language to add static types solely to get performance seems like a hack to me. Make the dynamic language fast enough that you don't need static types. I can appreciate it was an explicit design decision. My calling it a "hack" is to blunt claims that Clojure is faster than equivalent JRuby code, when in actuality the Clojure code is not equivalent. Clojure doing fully boxed math performs similarly to JRuby doing fully boxed math. Apples to apples instead of apples to statically-typed oranges. That said, I have wanted to do the same in JRuby. I do not have the freedom to make such a decision for Ruby, however, and Matz (Ruby's creator) has said there will never be static types. So...I will continue to work to make dynamic-typed math as fast as possible, and push the JVM to help me as much as it can. I won't hack around it :)
- cemerick 15y agoIt's a narrow point, but the coincidence of "make the dynamic language fast enough that you don't need static types" and talk about equivalent perf using boxed math reminds me of the old saw about a sufficiently smart compiler[1]. Yeah, maybe the hotspot/jrockit wizards will be able to wave a wand and make everything fast. But, until the stars align in that department,[2] being able (and in Clojure's case, defaulting) to fast, static, primitive math is a good thing IMO, and really, really important to getting work done in certain domains today. In the meantime, I greatly appreciate your pushing. :-D [1] http://c2.com/cgi/wiki?SufficientlySmartCompiler http://c2.com/cgi/wiki?SufficientlySmartCompiler [2] e.g. http://blogs.oracle.com/jrose/entry/fixnums_in_the_vm http://blogs.oracle.com/jrose/entry/fixnums_in_the_vm
- headius 15y agoI certainly agree. As an implementer of Ruby, I've wanted type-hinting escape hatches to make my job easier. Given that they're likely never going to happen, I will continue to optimize the hard way and work closely with JVM guys :)
- rbranson 15y agoJRuby generates direct, "static" dispatches to the Fixnum class when you throw the --fast flag. However, this is not backwards compatible with MRI Ruby, so it's not default. Clojure does not attempt to maintain compatibility with anything, so there you go.
- fogus 15y agoAiyayyay. Were to begin. calls are made via a known path to a specific function, and only via rebinding can that target change. The general case goes straight through. This is half true. The rebinding via def will change the target, but the call always happens via a lookup through a volatile. In fact, it's this very chain that can benefit from invokedynamic. If Clojure had to deal with dynamically selecting a method based on a target object type Clojure's protocols are polymorphic on the type of the first argument. The protocol functions are call-site cached (with no per-call lookup cost if the target class remains stable). This is another place where invokedynamic would help. benefit out of invokedynamic...if it hadn't already added hacks and syntax I think you're mixed up here. The JVM already optimizes classes and interfaces. All that Clojure's type hints allow you to do is to help the compiler in the cases where it's unable to infer the proper type. Hinting is not always necessary and better inferencing will start chipping into the remaining cases. JRuby compares favorably to Clojure without the typing syntax, performance-wise, which is quite acceptable to me. With invokedynamic That's because JRuby is awesome tech. You've certainly set the bar high for dynamic dispatch that invokedynamic has yet to meet. as the Hotspot guys optimize invokedynamic. What's the over-under on it happening by Java8? Java9?
- headius 15y agoI will grant I do not know the details of Clojure's dispatch protocols, but I've always felt like there's more that invokedynamic could do. Sounds like that's the case. My statements were based mostly on brief discussions with Rich about how dispatch happens...which made most of them sound pretty static in nature. Regarding invokedynamic optimization: Most of what I'm playing with will go into the first Java 7 update. I'm helping to validate that it works, it's fast, and it's ready for consumption.
- fogus 15y agothere's more that invokedynamic could do Definitely. As with anything, there are tradeoffs, so we'll likely hold off to see how it plays out. Most of what I'm playing with will go into the first Java 7 update. Hey no fair, you have inside information. All bets are off. This is great news actually. :-)