Home > OS >  Why do both j-- and --j throw exceptions in this LINQ code, but j - 1 does not?
Why do both j-- and --j throw exceptions in this LINQ code, but j - 1 does not?

Time:11-21

I'm new to C# and practising by writing a solution to the classic 100 doors problem. The below (and probably bad) code solves the problem:

internal class Program
{
    private static void Main(string[] args)
    {
        var doors = new bool[100];
        var ints = new int[100];
        ints = Enumerable.Range(1, 100).ToArray();
        for (int i = 1; i <= 100; i  )
        {
           ints.Where(j => j % i == 0)
               .Select(j => j)
               .ToList()
               .ForEach(j => doors[j - 1] = !doors[j - 1]); //This is the relevant line.
        }
        Array.ForEach(doors, i => Console.WriteLine(i));
    }
}

The line that I've put the comment on has surprised me. It works perfectly fine, but replacing it with either of the below throws System.IndexOutOfRangeException

.ForEach(j => doors[--j] = !doors[--j]);
.ForEach(j => doors[j--] = !doors[j--]);

Why are both of these invalid despite j - 1 being perfectly fine? It's my understanding that, in all circumstances, exactly one of --j and j-- will be equivalent to j - 1.

CodePudding user response:

It's my understanding that, in all circumstances, exactly one of --j and j-- will be equivalent to j - 1.

No, definitely not.

The two fail for different reasons though - one when j is initially 1, and the other when j is initially 100.

First consider this:

.ForEach(j => doors[--j] = !doors[--j]);

That decrements j twice, and in each case uses the value of j after the decrement has happened.

The left hand operand is evaluated first, so when j is 1, this ends up evaluating array indexes as:

doors[0] = !doors[-1];

Obviously, doors[-1] is invalid.

Now let's consider the second option:

.ForEach(j => doors[j--] = !doors[j--]);

This again decrements j twice, but in each array indexing operation uses the value of j before the decrement. So when j is 100, this ends up evaluating array indexes as:

doors[100] = !doors[99];

This time it's doors[100] which is invalid.

In your working code, you're using j - 1 for both indexes, without modifying j at all, so as j goes from 1 to 100, the array indexes you're using go from 0 to 99, which are valid.

I would strongly advise against using pre/post-increments/decrements in any expression or statement where you use the modified variable in more than one place - and definitely avoid pre/post-increments/decrements of the same variable multiple times in the same expression or statement.

  • Related