Some Creativity

Weblog of Siddharth Uppal

Archive for April 24th, 2008

Switch vs if-else-if

with one comment

This is an academic question. Which one is better?


        private string Foo(int value)
        {
            string result;

            switch (value)
            {
                case 10:
                    result = "something 1";
                    break;
                case 110:
                    result = "something 2";
                    break;
                case 150:
                    result = "something 3";
                    break;
                case 210:
                    result = "something 4";
                    break;
                default:
                    result = string.Empty;
                    break;
            }

            return result;
        }

or


        private string Bar(int value)
        {
            string result;

            if (value == 10)
                result = "something 1";
            else if (value == 110)
                result = "something 2";
            else if (value == 150)
                result = "something 3";
            else if (value == 210)
                result = "something 4";
            else
                result = String.Empty;
            return result;

        }

Even though both Foo and Bar do the same thing, Foo is better performance wise.

The compiler converts Foo into IL which roughly achieves the same thing as the following pseudo-code.


if value < 110 then
	if value == 10 then
		result = "something 1"
	else
		goto default_case
else
	if value == 110 then
		result = "something 2"
	else if value == 150 then
		result = "something 3"
	else if value == 210 then
		result = "something 4"
	else
default_case:
		result = String.Empty
end if	

Foo when converted to IL splits the search space with 110 in the middle which reduces the number of comparisons needed. As a result Foo will be faster than Bar. However, I wouldn’t advise you to worry about performance at this scale. As I said in the beginning, this question was only academic :)

Written by Sid

April 24th, 2008 at 8:08 pm

Posted in General

Switch is just If-Else-If

without comments

In an internal meeting of a bunch of developers at my current company, someone made the assertion that the Switch statement in C# (or Select Case in VB.NET) is just a compiler short-cut for writing a chain of If-Then-Else statements.

What do you think? Is that statement - true or false?

Take the following C# function for example:


        public string DoSomething(char c)
        {
            switch (Char.ToLower(c))
            {
                case 'e':
                case 'g':
                case 'k':
                    return "something 1";
                case 'a':
                case 'd':
                case 'h':
                case 'r':
                    return "something 2";
                case 'p':
                case 'i':
                case 'l':
                    return "something 3";
                default:
                    return "something default";
            }
        }

One of the ways to deal with the switch statement is for the compiler to treat the above switch statement as a sequence of If-then-else clauses, like so:


           char lowerC = Char.ToLower(c);
            if (lowerC == 'e' || lowerC == 'g' || lowerC == 'k' )
                return "something 1";
            else if (lowerC == 'a' || lowerC == 'd' || lowerC == 'h' || lowerC == 'r' )
                return "something 2";
            else if (lowerC == 'p' || lowerC == 'i' || lowerC == 'l' )
                return "something 3";
            else
                return "something default";

But, if you think about it, there’s a better way…

One can do better by having a lookup table to map each character that you can possibly see, to the address of the corresponding instruction which should be executed when that character is seen. With a lookup table like that, when you see ‘p’ for example, there’s no need to compare it against ‘e’, ‘g’, ‘k’… and all the other characters in the cases that preceded it in the switch statement. As a result, your code will be faster.

There’s a “switch” statement at the IL level which implements the jump-table concept. The generated IL for DoSomething looks like the following:


.method public hidebysig instance string
        DoSomething(char c) cil managed
{
  // Code size       125 (0x7d)
  .maxstack  2
  .locals init ([0] string CS$1$0000,
           [1] char CS$4$0001)
  IL_0000:  nop
  IL_0001:  ldarg.1
  IL_0002:  call       char [mscorlib]System.Char::ToLower(char)
  IL_0007:  stloc.1
  IL_0008:  ldloc.1
  IL_0009:  ldc.i4.s   97
  IL_000b:  sub
  IL_000c:  switch     (
                        IL_0063,
                        IL_0073,
                        IL_0073,
                        IL_0063,
                        IL_005b,
                        IL_0073,
                        IL_005b,
                        IL_0063,
                        IL_006b,
                        IL_0073,
                        IL_005b,
                        IL_006b,
                        IL_0073,
                        IL_0073,
                        IL_0073,
                        IL_006b,
                        IL_0073,
                        IL_0063)
  IL_0059:  br.s       IL_0073
  IL_005b:  ldstr      "something 1"
  IL_0060:  stloc.0
  IL_0061:  br.s       IL_007b
  IL_0063:  ldstr      "something 2"
  IL_0068:  stloc.0
  IL_0069:  br.s       IL_007b
  IL_006b:  ldstr      "something 3"
  IL_0070:  stloc.0
  IL_0071:  br.s       IL_007b
  IL_0073:  ldstr      "something default"
  IL_0078:  stloc.0
  IL_0079:  br.s       IL_007b
  IL_007b:  ldloc.0
  IL_007c:  ret
}

Here’s what the compiler generated code to do:

  • The ordinal value of ‘a’ (i.e. 97) is subtracted from the character passed to the function.
  • As a result for characters between ‘a’ and ‘r’, you’d see values between 0 and 17 (both included).
  • For each value between 0 and 17, the compiler then specified the label of the instruction that the execution should jump to, in the IL switch statement.
  • Notice IL_0059: if the value does not lie between 0 and 17, code has been generated to directly jump execution to IL_0073 and we get ready to return “something default”.

Sweet, isn’t it?

Does the compiler always handle “switch” this way?

Nope. If the range of the values specified in the case clauses is large, creating a table as explained previously, will cause wastage of memory. So a function like the following won’t be utilizing the IL “switch” statement and will be treated like a sequence of “if-then-else” statements. However, for efficiency, the order of comparisons might be different from the order in which “case” clauses were specified in your code (more info).


        public string DoSomethingElse(int bla)
        {
            switch (bla)
            {
                case 10:
                case 45:
                case 99:
                    return "something 1";
                case 21:
                case 1091:
                    return "something 2";
                case 2048:
                case 256:
                case 1072:
                    return "something 3";
                default:
                    return "something default";
            }
        }

Here’s a link to an article that presents some findings from comparing execution speed of “switch” against “if-else-if”. But like I said earlier, this qualifies as micro-optimization and there’re most probably other things in your code you should be worrying about.

Written by Sid

April 24th, 2008 at 3:22 pm

Posted in .NET, General, Tech/Hacks

Tagged with , ,