Personally, I'd like to see more programming done in languages that simply don't allow integer overflow in the first place. Most current languages have arbitrary-precision integers; well-implemented arbitrary-precision integers are quite efficient when they fit in a machine word, and as efficient as possible when larger. Sure, you'll lose a bit of performance due to checks for overflow, but those checks need to exist anyway, in which case it seems preferable to Just Work rather than failing.
Checks are the smallest cost of bignums. Dynamic allocation isn't free, it's terribly expensive. Dereferencing pointers isn't free, it's terribly expensive. It's one thing for a scripting language (where people expect poor, inconsistent performance) to have automatic bignums but it's quite another for a language in which people will be writing performant code to have automatic bignums. They introduce a thousand difficult-to-debug edge cases that slow your code to 1/3 or 1/5 (or 1/100th or 1/1000th) speed. I don't know about you, but I don't consider that "Just Working."
Don't get me wrong, they could be a useful feature, perhaps even one which should be enabled by default in Swift (I'd argue against them, but I wouldn't be entirely unsympathetic to their proponents). However, they aren't for everyone and they don't come cheap.
context matters. most arithmetic operations are not performed in hot loops or are not performed on large vectors. I think its better to have a default where correctness and error prevention are gained at the cost of speed. When the speed is needed an explicit choice to use an unsafe but faster performing number type would be the prerogative of the programmer. Its important to have both options available, because context matters.
Isn't the alternative introducing a thousand difficult-to-debug edge cases that cause your code to produce incorrect output, or crash? I'd rather the default setup be "can be slow sometimes". If you're writing performance-sensitive code where you want to control the overflow behavior, make that an option, but not the default.
In the context of Swift, it would make a lot of sense to me for Int to be a bignum with no built-in limits on range. The common case of looping over a small set of values, computing indexes for UI elements, etc. will fall within the range of machine native integers and remain fast. If you blow out the limits, your code will still work. If you want control/speed, use one of the provided integer types with an explicit width.
First of all, I'm all for overflow traps and I'm quite happy with bignums in my scripting languages. I only claim:
1. There is a large class of languages where they do not make sense as a default.
2. The most sensible approach is to fastlane the all-int native case, but this comes at the cost of a preciptitous drop in speed the moment even a single bignum happens.
> Isn't the alternative introducing a thousand difficult-to-debug edge cases that cause your code to produce incorrect output, or crash?
Unintentional bignums are usually bugs, so incorrect output / crash is usually the best one could hope for anyway. People understand that programs have bugs and crash, but the combination of slowness with incorrect output is a special recipe for infuriated users (I waited 30 minutes for the file to load and then it crashed?!?!).
You sound like you have more experience with this than I, so take the following with that in mind....
My experience with this has mainly been in languages like Python, where bignum performance is way down on the list of worries, and C, where you wrap if you're lucky and end up with exploitable security vulnerabilities if you're not. I don't believe I've seen a language at work which traps overflows.
My experience with C has been that overflows (which would be unintentional bignums in another environment) are almost always one of:
1. Underflow of unsigned values used for sizes, especially for memory allocation, which causes a request for vast quantities of memory.
2. Computations on large quantities without thinking about how large they can be. File sizes are a really common example of this, especially since they fit into 32 bits for so long.
3. Reading textual data containing integers that either doesn't specify how large they can be, or specifies it but the specification got ignored. A fun example of this was the Twitpocalypse, when Twitter collected enough tweets for the tweet IDs to overflow signed 32-bit integers and broke a ton of clients.
#1 is an error, and crashing would be fine. That's usually what happens in C anyway, just in a somewhat more confusing manner because you get an error trying to allocate 4 billion bytes of memory rather than the more obvious "can't put -1 in here" that actually happened.
#2 is pretty much the poster child for automatic bignums. The downside being potential slowness, but most aren't performance sensitive.
#3 is an interesting case. I'm not sure that using a language "integer" type is even the right way to represent an ID from a remote service, even if that ID happens to be an integer. But automatic bignums would have prevented this problem, even if the design wasn't necessarily right to begin with.
As far as I know (and I realize it's probably hard to tell), I haven't seen bugs where automatic bignums would produce the wrong answer. They can be bugs (e.g. #1 above, possibly #3) but they don't involve incorrect output.
Anyway, to me it just makes sense for the default behavior to be correctness. When you write "a + b" without taking special measures, the result should be the right answer in a mathematical context. If you want bounds checking, that should be made explicit. (A way to create configurable integer types with arbitrary bounds could be nice.) If you want wrapping, that should be made explicit too. And if you want performance at the potential expense of correctness at the edges (presumably because you either know you won't hit the edges, or they behave the way you want them to) then that ought to be opt-in, not opt-out.
That's not easy either as it'd require very heavy inlining by the compiler. Functions that accept just 'integer' have to check if the value is a native number or actual reference and process differently.
C/C++,Java* ,C# have it easier there - when you pass 'int'/'long' the receiver knows it's a native number.
* Fixnums support (headless objects) needed for non-Java lanaguages on JVM is still unimplemented to my knowledge[0]
> That's not easy either as it'd require very heavy inlining by the compiler.
Right, bignums need to be a language feature, not a library feature. Compilers with native bignum support often have ways of handling native unboxed single-register numbers, and then branching to full bignum routines when needed. Haskell can do that, for instance.
Also, you can use the standard trick of decreasing the maximum single-register size and using the extra bits to identify indirect objects.
>>Also, you can use the standard trick of decreasing the maximum single-register size and using the extra bits to identify indirect objects.
That's given, you still pay the price (like mask/shift), though. That was the part the "languages like C/C#/Java have it easier" about. The point is mostly that even if built-in support (interrupts) exist in the hardware, bignums still need quite a lot of extra code in-place, plus a good optimizing/inilining compiler.
Personally I am happy with constrained integer types - else the entire stack (incl. storage) must support bignums and often (like almost always) going out of range would be a bug actually.
I am temped to do Bill Gates here and say: 64bits should be enough for everyone (in the common case). If not - using SSE like maths it's an option too. Using bignums by default would make everyone suffer - they do come with a price and the hardware can't support such a bizarre beast naturally.
> Sure, you'll lose a bit of performance due to checks for overflow...
Which is why the author wants support for integer overflow traps. He even mentions Python, which does what you describe, and suggests that other languages don't do this precisely because of the performance hit for which he's proposing a solution.
You seem to be defining "current languages" to mean "languages that have recently originated" rather than "languages that are currently used". But the languages that are heavily used currently - C, C++, C#, and Java - while they have bignum packages available, the integers within the languages themselves are not arbitrary-precision.
It isn't just recent languages that have this. One of the confusions of many folks starting to use most lisps is actually that they typically have very solid number libraries. Such that it is sometimes confusing to see 1/3 as the number you are holding, instead of an approximation.