++1 for auto promotion, average code
is complex enough, lets not add
more incertainty with overflow
exceptions.
Data changes overtime and
discovering it in production with
an overflow exception is less than
elegant.
Degraded performance is much more
acceptable in production than a crash
over an unhandled exception ....
Again, if performance is critical for
a library or an application then it's up
to its designer to take action.
For the other folks, they will get
the best implementation according
to the number size they crunch in
their data. No need for them to pay
the price for control they do not
need yet.
Luc P
Sent from my iPod
On 2010-06-22, at 12:44 AM, Mark Engelberg <mark.engelb...@gmail.com>
wrote:
The new uber-loop is fantastic.
So I guess the main point still to be finalized is whether the default
arithmetic ops will auto-promote or error when long addition
overflows.
Playing around with the latest equals branch:
user=> (def n 9223372036854775810)
#'user/n
user=> (* (/ n 3) 3)
9223372036854775810N
user=> (* (/ n 2) 2)
java.lang.ArithmeticException: integer overflow
user=> (def x (/ n 4))
#'user/x
user=> (+ x x x x)
9223372036854775810N
user=> (+ (+ x x) (+ x x))
java.lang.ArithmeticException: integer overflow
user=> (range (- n 2) n)
(9223372036854775808N 9223372036854775809N)
user=> (range (- n 3) n)
java.lang.ArithmeticException: integer overflow
I understand exactly why some of these work and some of these don't.
My main point here is to illustrate that without the full numeric
tower supported by the default ops, there can certainly be some
surprises. There is a "pathway" with the standard ops from longs to
rational numbers to bigints, but you can't cross directly from longs
to bigints. Similarly, you can roundtrip from bigints to rationals
and back, but can't roundtrip from bigints to longs and back. So the
results of computations depends on the path you follow. Maybe we can
live with these idiosyncrasies for the speed benefits, but this is
worth being aware of.
The range example is something that is easily enough fixed. Probably
if this branch becomes the standard, range should be modified so that
if the *upper bound* is a bigint, inc' is used rather than inc to
generate the range. But I think this illustrates the kinds of issues
we're headed towards, regardless of which default is chosen -- people
who write libraries will be choosing between overflow and auto-boxing
primitives, and it might not always be clear from documentation what
the consequences are. In the current implementation of range, it
works perfectly fine with longs, and it works perfectly fine with
bigints, but it breaks when your lower and upper bounds cross the
boundary. This is exactly the kind of thing that might not be thought
of when making test cases, so errors like this could lurk for quite a
while without being spotted.
The people on the side of overflow-error-as-default feel that these
sorts of runtime errors are no more problematic than the many other
sorts of runtime errors that can result in Clojure, such as an
out-of-bounds exception when accessing a vector. But I see these
types of errors as very different. An out-of-bounds exception is easy
enough to prevent -- there is a simple test you can include in your
code to make sure your index is in bounds before you access your
vector. But I think it's much harder to determine in advance whether
a sequence of computations will "cross the long boundary" for all the
possible inputs.
This is probably the main reason I continue to advocate for
auto-promoting ops as the default. Error-upon-overflow adds an
element of run-time risk, and requires careful thought and additional
testing to achieve the same level of reliability. I *want*
error-upon-overflow operations to be slightly harder to use so that
library writers will use them judiciously and consciously, and be very
aware of the extra effort they need to go to test their functions for
all numbers, clearly documenting any restrictions on the kinds of
numbers that are permitted.
Like I said before, Clojure's built-in range can easily be adjusted to
work well for speed *and* handle both longs and bigints gracefully.
But it serves as a good example of how the two defaults will affect
library writers. If auto-promotion is the default, most library
writers will just use the +,*,-,inc,dec operators and it would work
for all numbers right out of the box. A library writer who wants to
optimize for speed would have to go to a bit of extra effort to add
the apostrophes, and would hopefully at that point give some careful
thought as to what the consequences will be, catching the fact that
this will break ranges that span from longs to bigints, and adjusting
the code accordingly. On the other hand, if overflow-on-error is the
default, this is what most people will use, and we'll end up with a
lot of code that breaks when crossing the long boundary.
I don't use any bigints, or anything even close to overflowing a long,
in the kind of code that I write for work. If error-upon-overflow
wins as the default, I'll gain performance benefits with no immediate
downside. But ultimately, I feel that anything that helps me reason
about and trust my code, and helps me trust the robustness of code
written by others that I rely upon, is a principle worth fighting for.
--
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
--
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