3

I used ILSpy to reflect into the LINQ's Sum method and noticed that it just does a foreach with the checked keyword. But if an int has a defined maximum and you try to go over it, why doesn't it throw an error by default. Assuming you don't use Sum and you do your own foreach without checked, you will not get an exception, it will just give you a garbage value if you go over the maximum int value, but I don't see the reason why this is not just default behavior. If you need something bigger than an int, then don't use an int.

Xaisoft
  • 45,655
  • 87
  • 279
  • 432
  • 2
    You can enable checked arithmetic in your project settings. I do that for almost all of my projects. – CodesInChaos May 17 '13 at 12:52
  • @CodesInChaos - OK, I never knew this. Thanks for pointing this out, but why still isn't this default behavior? From my own perspective, if I know a value is going to exceed the maximum of an int, I will use something bigger. – Xaisoft May 17 '13 at 12:56
  • 1
    One place where `unchecked` is useful is `GetHashCode` where it doesn't really matter if the `int` overflow. It just need to be fast and fairly accurate. `Equals` is used anyway to determine if the two objects are really equal if `GetHashCode` returns the same value. http://stackoverflow.com/a/263416/284240 – Tim Schmelter May 17 '13 at 12:56
  • @CodesInChaos - And if you do it in project settings, does it do it for ints, shorts, etc? Is there a valid reason why you would want to throw an error for an arithmetic overflow for an int, but not a short? – Xaisoft May 17 '13 at 12:57
  • performance reasons? http://stackoverflow.com/questions/13259408/why-doesnt-c-sharp-use-arithmetic-overflow-checking-by-default – NDJ May 17 '13 at 12:57
  • @NDJ - I actually did a search for this and didn't find it. Thanks. – Xaisoft May 17 '13 at 12:59
  • See also the thread [Why don't languages raise errors on integer overflow by default?](http://stackoverflow.com/questions/103654/), a near duplicate. – Jeppe Stig Nielsen May 17 '13 at 13:00

2 Answers2

4

Checked operations are significantly slower than unchecked:

const int startVal = Int32.MaxValue - 1000000;
Stopwatch sw = new Stopwatch();

sw.Start();
int i = startVal;
while (i < Int32.MaxValue)
{
    unchecked
    {
        i++;
    }
}
sw.Stop();
Console.WriteLine("Unchecked: " + sw.ElapsedTicks + " ticks");

i = startVal;
sw.Restart();
while (i < Int32.MaxValue)
{
    checked
    {
        i++;
    }
}
sw.Stop();
Console.WriteLine("Checked: " + sw.ElapsedTicks + " ticks");

Result:

Unchecked: 241 ticks
Checked: 1992 ticks

So using checked results in a performance hit, and since overflow is relatively rare (who actually counts up to Int32.MaxValue?), C# uses unchecked by default.

thecoop
  • 45,220
  • 19
  • 132
  • 189
  • But since it won't matter in 99% of the code it'd be better to enable it by default and only disable it selectively. – CodesInChaos May 17 '13 at 13:03
  • Didn't think it would actually be that much? What did you run those metrics on? – Xaisoft May 17 '13 at 13:03
  • Standard .NET 4 console application in release mode – thecoop May 17 '13 at 13:04
  • 2
    Sure, but your code example has the disadvantage that in one case an exception is raised and dealt with by the `catch` block, while in the other case time is not wasted on that. Maybe you should change to `while (i != int.MaxValue)` and drop the `try`-`catch`? – Jeppe Stig Nielsen May 17 '13 at 13:05
  • @JeppeStigNielsen: oops, didn't spot that. I've edited & re-ran the program. – thecoop May 17 '13 at 13:12
  • @thecoop - When I run it, I get `7092ms for unchecked` and `6891ms for checked`. I'm just running it on an `i7 CPU at 2.9GHz with 8 GB Ram on a 64 bit OS` – Xaisoft May 17 '13 at 13:23
  • Ok, I ran it in LinqPad first and then in VS and `checked` rand somewhat slower. – Xaisoft May 17 '13 at 13:28
  • @Xaisoft: were you running in debug or release mode? Was the debugger attached? – thecoop May 17 '13 at 13:37
2

I don't see the reason why this is not just default behavior

There may be costs involved in performing such checks - either checking of processor flags, or (if using a larger register internally) checking the upper contents of a register. And basic assignment can be an operation occurring inside the tightest of loops - the costs could be appreciable, and not everyone should have to pay.

So you get to choose whether you want those checks to occur.

Damien_The_Unbeliever
  • 234,701
  • 27
  • 340
  • 448
  • OK, That makes sense, but I am not hardware expert, but with the advance of hardware today, does this really matter any more? That maybe a stupid statement, but like I said, I am not a hardware expert and I am not sure how much performance we are talking about. – Xaisoft May 17 '13 at 13:02
  • Well, @thecoop seems to be doing a good job of giving you benchmarks - and as I say, such basic assignment happens a *lot*, and I'd be willing to wager that in 99.9999% of cases, there's never any *risk* that an overflow will occur. – Damien_The_Unbeliever May 17 '13 at 13:13