On 16 January 2011 05:35, Jason Wolfe <ja...@w01fe.com> wrote: >> (a) unsafe/incorrect value on overflow/fastest/unifiable* vs. >> (b) safe/error on overflow/fast/unifiable vs. >> (c) safe/promoting on overflow/slow/not-unifiable > > If I understand correctly, the issue with auto-promotion is that we > have to box the output of an operation even if it turns out to fit in > a long, since the compiler must specify whether the result will be > long or Object. > > This is probably a stupid question, but since Clojure is already > testing for overflow in (b) to throw an exception, would it be > possible to jump into an alternative (c)-type compilation of the > function just-in-time to promote on overflow instead? It seems like > this could achieve the performance of (b) while still allowing for > auto-promotion (albeit perhaps with a performance hit in that case, > code bloat, compromises about how many versions to compile, etc.).
When Clojure compiles your function, it emits JVM bytecode for a new class which is then loaded by the classloader. That JVM bytecode defines a function (well, a method as far as the JVM is concerned) which returns either a primitive type or Object. Your suggestion would involve redifining the class while it is executing. That's not possible on the JVM. Even if it were possible -- your function now returns Object instead of long. But the variable that the result of your function is about to be assigned to is a long, because that's what your function used to be defined to return, and the next bytecode operation in the calling code is the one that subtracts a primitive long from a primitive long. Now what? Fundamentally, Clojure has to contend with the fact that the JVM as a platform distinguishes between primitives and Objects. The bytecode operations which the Clojure compiler emits have to differ based on that distinction. Essentially, the distinction cannot be magicked away, because JVM bytecode is going to statically enforce that we're either working with a (long or double) or a (Long or BigInt or BigDecimal or whatever), and never the twain shall meet. So if we ever want to be able to access the speed of the primitive bytecode operations, then the primitive/Object distinction has to leak into Clojure. (Or we have to redefine or move away from the JVM. Obviously not really an option, but I mention it to point out that the reason Clojure has to make this decision is that it's a hosted language. That has a lot of benefits; this is one of the trade-offs we have to contend with in return.) I think everyone agrees that it's important to make the speed of the primitive bytecode operations available in Clojure (whether or not it's the default), so that rules out the option of always doing auto-promotion. I think it's probably also agreed that allowing unchecked overflow is not good (at least, no one seems to be arguing for it). So we're left with option (b) and a choice about the default behaviour of the core library functions. If we default to boxing and treating everything as an Object then we get the nice comfy numeric tower that we never have to worry about, but the default case suffers in performance. Otherwise, we default to primitive, and accept that if we're dealing with numbers which might get bigger than Long.MAX_VALUE, then we might need to explicitly use a BigInt to get contagion, or use an operator like +' which will always deal with Objects. By choosing to make speed the default preference in the core library functions, I suppose there's more for Clojure programmers to think about, because whenever you're dealing with numbers, you need to have in the back of your mind the question of whether this might ever need to be bigger than Long.MAX_VALUE, and so whether you might need +' instead of +. Then again, how often do you write code that might be doing maths with numbers that big and not realise it? For that matter, how often do you write code that might be doing maths with numbers that big and not spend time thinking carefully about its performance anyway? -- 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