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

Reply via email to