-2

If I have some foreach loops e.g.

foreach (ObjectA a in getAs(param1))
{
    foreach (ObjectB b in getBs(param2))
    {
        //compare a & b
    }
}

Assuming I don't make any edits to the returning lists (they are the same list returned), will the compiler be smart enough to only call getAs() & getBs() once, each? Will it even be smart enough to know that it should convert them to a dictionary?

Will the fact that it is eventually interacting with a SQL database, through LNQ, make a difference (e.g. perhaps the code assumes that a SQL database can change at any moment, but maybe it can do a check to see if it's changed?)

TruthOf42
  • 2,017
  • 4
  • 23
  • 38
  • 1
    Why don't you `debug` ?? – huMpty duMpty Jul 01 '14 at 15:09
  • I believe you **may** be talking about this [What is the difference between a reference type and value type in c#?](http://stackoverflow.com/questions/5057267/what-is-the-difference-between-a-reference-type-and-value-type-in-c) – Liam Jul 01 '14 at 15:10
  • @huMptyduMpty I believe debugging code automatically removes any improvements the compiler makes (i.e. it doesn't try to simplify the code when you debug) – TruthOf42 Jul 01 '14 at 15:18
  • @Liam Are you implying that compilers don't try to simplify code involving reference types at all, or at least not nearly to the extent they do for value types? – TruthOf42 Jul 01 '14 at 15:20
  • Compilers do no simplify code (full stop). Value types and reference types are about where the values a stored within the framework (stack or heap). This has little or no relation to how you use these variables within your code or the outcome of the compiled code. You seem to expect the compiler to improve the efficiency of your code. This isn't going to happen. That's down to you. – Liam Jul 01 '14 at 15:30

2 Answers2

2

The short answer is No, but the long answer has more to do with the way your code is written rather than the efficiency of the compiler.

In your first foreach loop, you obtain the source once, and iterate through its elements, effectively calling the method only once in order to obtain the source, but the nested foreach loop is called once for every iteration in the outer loop, and since the compiler has no way of knowing if the output of the method in the nested loop won't change, it actually makes sense for it to always call the method in order to obtain the source to iterate through.

In this case you need to improve your logic and avoid unnecessary calls to methods if you know the output will be the same, specially if you know that there is some resource consuming operation (such as a call to a DB) going on inside that method.

For the sake of giving a detailed answer, i tried your statements in the following program:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace StackOverflow
{
    public class Class1
    {
        public static void Main(string[] args)
        {
            var serv1 = new Testserv1();
            foreach (int x in serv1.CallA())
            {
                foreach (int y in serv1.CallB())
                {
                }
            }
            Console.WriteLine(string.Format("Calls to A: {0}", serv1.ACount));
            Console.WriteLine(string.Format("Calls to B: {0}", serv1.BCount));
            Console.ReadLine();
        }

    }

    public class Testserv1
    {
        private static int CallACount = 0;
        private static int CallBCount = 0;

        public int ACount {
            get
            {
                return CallACount;
            }
        }

        public int BCount
        {
            get
            {
                return CallBCount;
            }
        }

        public Testserv1()
        {
            //InitializeComponent();

        }

        public List<int> CallA()
        {
            CallACount++;
            return new List<int>() {
                1,2,3,4,5,6
            };
        }

        public List<int> CallB()
        {
            CallBCount++;
            return new List<int>() {
                7,8,9,10,11,12
            };
        }


    }
}

The output for the previous code is:

Calls to A: 1
Calls to B: 6
M.K.S.
  • 171
  • 3
0

Given the information presented in your question, there is no legitimate reason to assume that the compiler would convert to a dictionary. In fact, there is no reason for a dictionary. Why would one expect the compiler to divine a unique key from a method call result?

The question posed does not provide sufficient information to even reply with a relevant response.

Necessary details include: What are the return types of the methods getAs and getBs? On what basis are the comparisons being made?
What is the usage and result type expected from the loop?

Each loop is using a different object, on what basis would one assume the compile would optimize in any manner given the complete lack of forthright information?

Given a more specific example such as this:

List<string> intersection = new List<string>();

foreach (string a in GetaList())
{
    foreach (string b in GetbList())
    {
        if (a.Equals(b))
        {
            intersection.Add(a);
        }
    }
}

The assembly (F11 to step in, CTRL-F11 to view assembly) would indicate that the GetbList is actually getting called for each iteration, at least in debug mode.

I believe the answer to your question is: No, the compiler is not optimizing the inner method call for you. If you want the inner method call to occur only once, make the call outside the outer loop.

Lemiarty
  • 124
  • 10