
On 30 March 2010 17:05, Chad Nelson <chad.thecomfychair@gmail.com> wrote:
Now that's an argument I can finally agree with. :-)
Yay! =]
Here's how I propose to solve it: make a "core" version of the integer class and functions, with no exception-blocking and no Not-a-Number value, in the namespace xint::core. Then make the main integer class and functions in namespace xint, with exception-blocking, the Not-a-Number value, and maybe infinity values.
I like the idea. Here's a brain dump of a slightly different way it could look: The user would see two classes, finite_xint and nothrow_xint. (Names subject to refinement, of course.) They'd share representation somehow for move semantics, CoW, or whatever support (which means that mixing the two is still efficient, since a temporary of one can turn into a temporary of the other cheaply). A finite_xint maintains the invariant that it always holds a specific, finite value. A nothrow_xint, on the other hand, allows for special values. Clearly converting a finite_xint to a nothrow_xint would always succeed. Converting a nothrow_xint to a finite_xint would throw an exception if the number isn't finite. Consider for this post at least that they have bidirectional implicit conversions. (The throwing implicit conversion is scary, so perhaps not a good idea, but you'll see why I kept it anyways. It should also mean that mixed operations would be ambiguous -- like finite_xint() + nothrow_xint() -- which would be a good thing, imho.) Then just about every function currently in the library would change to accept a finite_xint. That pretty much gives the current library behaviour, but with at least two advantages. 1) No need to explicitly spell out the "throws on NaN" behaviour for every function, since it's clear from the argument type that passing a non-finite number will give an exception in the implicit conversion. (And there's no possible efficiency complaint about the check, since if you just pass a finite_xint in the first place, there's no check done.) 2) For sqrt, division, invmod (and any other functions that can give NaN), you choose the behaviour by where you store it. finite_xint x = sqrt(finite_xint(-1)); will throw even though the sqrt returned a NaN. If you'd rather check for NaN yourself, then you just do nothrow_xint x = sqrt(finite_xint(-1)); (And, again, with move semantics, it's guaranteed that there's no excess copying involved even when storing to a different type.) It does mean that the NaN is essentially still a signalling NaN, though. Since I personally prefer a quiet(-as-possible) NaN, I'd want it taken another step further. Another version of every operation is added, taking nothrow_xints instead; the current NaN-returning functions are renamed with a nothrow_prefix, so for instance nothrow_sqrt(finite_xint(-1)) == nothrow_xint::NaN(); and the current NaN-returning functions are re-writen to throw internally so they can return finite_xints. (Initially all these functions would be simple wrappers, but plausibly they'd eventually be rewriten using the unspecified common representation either by someone with a slow try-catch implementation or by the "exception-haters".) All of the nothrow_xint functions would be noexcept, since bad_alloc or length_error would result in +/-Inf and any domain error would give a NaN. That would allow people to choose between fail-hard-and-fast code and safely-do-as-much-as-we-can code as the situation requires. Mixing them will still remain reasonable, since calling is_odd(nothrow_xint::NaN()) would end up treating it like a signalling NaN if -- as is likely -- there's no implementation of is_odd that takes a nothrow_xint. And if only a nothrow_xint-taking version of some function is available, finite_xint users will still be happy since they'll still get the exception; it'll just be a bit later (when they store the result instead of ASAP). P.S. Upon further reflection, please keep x/0 resulting in NaN. I agree that multiple zeros in an integer class is evil, and that means that 1/(1/-Inf) and 1/(1/Inf) have to evaluate to the same thing, so it should be NaN.