If Statements Vs Object Oreiented practices

When i was browsing, i found that there is a campaign called "The Anti If Campaign" https://www.antiifcampaign.com/code-recruitment.html. They are very much related to the Agile team. I read saw a claim that says the "IF Statements" are difficult to maintain and to add/delete codes inside them. They claim to use inheritance and Object Oriented best practices to enhance the code.

So i said to myself how can that impact performance? Then i decided to create this example:

Let’s take it step by step
if i have two products A & B
A comes in three flavors C, D & E.
C comes in three flavors too F, G & H.

so when you come to the bottom of it, you see that there are actually 6 products. C, D, E, F, G & H.

The If-Statement-Way

If i have a code that will simulate that scenario, it would be like this:

if( a == 1)

{

if (b == 2)

{

if (c == 3) doSomething(a, b, c);

else if (c == 4) doSomething(a, b, c);

else doSomething(a, b, c);

}

else if (b == 3) doSomething(a, b, c);

else doSomething(a, b, c);

}

else doSomething(a, b, c);

The Anti-If-Way

If you follow the people who are "Anti IF Statement", i would write the code in a different way:

    public abstract class MyBaseClass

    {

        public int a, b, c;

        public MyBaseClass() { }

        public abstract void doSomething();

    }

    public abstract class AEqual1Class : MyBaseClass

    {

        public AEqual1Class() {a = 1;}

    }

    public abstract class BEqual2Class : AEqual1Class

    {

        public BEqual2Class(){b = 2;}

    }

    public class CEqual3Class : BEqual2Class

    {

        public CEqual3Class(){c = 3;}

        public override void doSomething(){…}

    }

    public class CEqual4Class : BEqual2Class

    {

        public CEqual4Class(){c = 4;}

        public override void doSomething(){…}

    }

    public class CEqualOtherClass : BEqual2Class

    {

        public CEqualOtherClass() {c = 100;}

        public override void doSomething(){…}

    }

    public class BEqual3Class : AEqual1Class

    {

        public BEqual3Class(){b = 3;c = 100;}

        public override void doSomething(){…}

    }

    public class BEqualOtherClass : AEqual1Class

    {

        public BEqualOtherClass(){b = 100;c = 100;}

        public override void doSomething(){…}

    }

    public class AEqualOtherClass : MyBaseClass

    {

        public AEqualOtherClass(){a = 100;b = 100;c = 100;}

        public override void doSomething(){…}

    }

The Results

So i decided to compare between the two methods in all cases by calculating the execution time of each one and below are the results:

Test

in case of IF statements

in case of *NO* IF statements

a=100, b=100, c=100

1.00619492645912 seconds

0.499456347674696 seconds

a=1, b=100, c=100

0.333323067994865 seconds

0.249895601507773 seconds

a=1, b=3, c=100

0.200379324787097 seconds

0.166854522360645 seconds

a=1, b=3, c=100

0.142798249143871 seconds

0.125212235872841 seconds

a=1, b=3, c=4

0.111325223259706 seconds

0.10132541944173 seconds

a=1, b=2, c=3

0.0910784876580769 seconds

0.0835666302589329 seconds

To be honest the results came us a surprise to me J. But I’ve learned something today.

Updated --- some people wanted to get the test project

Test Project

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

namespace AntiIfStatements

{

class Program

{

static void Main(string[] args)

{

QueryPerfCounter counter = new QueryPerfCounter();

// Calculate time per iteration in nanoseconds

double result;

counter.Start();

counter.Stop();

Console.WriteLine("in case of IF statements a=100, b=100, c=100");

counter.Start();

IIfStatements(100,100,100);

counter.Stop();

result = counter.Duration(1);

Console.WriteLine(result / 1000000000 + " seconds");

Console.WriteLine("in case of *NO* IF statements a=100, b=100, c=100");

counter.Start();

NoIfStatement(new AEqualOtherClass());

counter.Stop();

result = counter.Duration(2);

Console.WriteLine(result / 1000000000 + " seconds");

Console.WriteLine("in case of IF statements a=1, b=100, c=100");

counter.Start();

IIfStatements(1, 100, 100);

counter.Stop();

result = counter.Duration(3);

Console.WriteLine(result / 1000000000 + " seconds");

Console.WriteLine("in case of *NO* IF statements a=1, b=100, c=100");

counter.Start();

NoIfStatement(new BEqualOtherClass());

counter.Stop();

result = counter.Duration(4);

Console.WriteLine(result / 1000000000 + " seconds");

Console.WriteLine("in case of IF statements a=1, b=3, c=100");

counter.Start();

IIfStatements(1, 3, 100);

counter.Stop();

result = counter.Duration(5);

Console.WriteLine(result / 1000000000 + " seconds");

Console.WriteLine("in case of *NO* IF statements a=1, b=3, c=100");

counter.Start();

NoIfStatement(new BEqual3Class());

counter.Stop();

result = counter.Duration(6);

Console.WriteLine(result / 1000000000 + " seconds");

Console.WriteLine("in case of IF statements a=1, b=2, c=100");

counter.Start();

IIfStatements(1, 3, 100);

counter.Stop();

result = counter.Duration(7);

Console.WriteLine(result / 1000000000 + " seconds");

Console.WriteLine("in case of *NO* IF statements a=1, b=2, c=100");

counter.Start();

NoIfStatement(new CEqualOtherClass());

counter.Stop();

result = counter.Duration(8);

Console.WriteLine(result / 1000000000 + " seconds");

Console.WriteLine("in case of IF statements a=1, b=2, c=4");

counter.Start();

IIfStatements(1, 3, 4);

counter.Stop();

result = counter.Duration(9);

Console.WriteLine(result / 1000000000 + " seconds");

Console.WriteLine("in case of *NO* IF statements a=1, b=2, c=4");

counter.Start();

NoIfStatement(new CEqual4Class());

counter.Stop();

result = counter.Duration(10);

Console.WriteLine(result / 1000000000 + " seconds");

Console.WriteLine("in case of IF statements a=1, b=2, c=3");

counter.Start();

IIfStatements(1, 3, 3);

counter.Stop();

result = counter.Duration(11);

Console.WriteLine(result / 1000000000 + " seconds");

Console.WriteLine("in case of *NO* IF statements a=1, b=2, c=3");

counter.Start();

NoIfStatement(new CEqual3Class());

counter.Stop();

result = counter.Duration(12);

Console.WriteLine(result / 1000000000 + " seconds");

Console.ReadLine();

}

static void IIfStatements(int a, int b, int c)

{

if( a == 1)

{

if (b == 2)

{

if (c == 3) doSomething(a, b, c);

else if (c == 4) doSomething(a, b, c);

else doSomething(a, b, c);

}

else if (b == 3) doSomething(a, b, c);

else doSomething(a, b, c);

}

else doSomething(a, b, c);

}

static void doSomething(int a,int b,int c)

{

System.Threading.Thread.Sleep(1000);

System.Console.WriteLine("\tvalues a={0}, b={1}, c={2}", a, b, c);

}

static void NoIfStatement(MyBaseClass MyClass)

{

MyClass.doSomething();

}

}

public abstract class MyBaseClass

{

public int a, b, c;

public MyBaseClass() { }

public abstract void doSomething();

}

public abstract class AEqual1Class : MyBaseClass

{

public AEqual1Class() {a = 1;}

}

public abstract class BEqual2Class : AEqual1Class

{

public BEqual2Class(){b = 2;}

}

public class CEqual3Class : BEqual2Class

{

public CEqual3Class(){c = 3;}

public override void doSomething()

{

System.Threading.Thread.Sleep(1000);

System.Console.WriteLine("\tvalues a={0}, b={1}, c={2}", a, b, c);

}

}

public class CEqual4Class : BEqual2Class

{

public CEqual4Class(){c = 4;}

public override void doSomething()

{

System.Threading.Thread.Sleep(1000);

System.Console.WriteLine("\tvalues a={0}, b={1}, c={2}", a, b, c);

}

}

public class CEqualOtherClass : BEqual2Class

{

public CEqualOtherClass() {c = 100;}

public override void doSomething()

{

System.Threading.Thread.Sleep(1000);

System.Console.WriteLine("\tvalues a={0}, b={1}, c={2}", a, b, c);

}

}

public class BEqual3Class : AEqual1Class

{

public BEqual3Class(){b = 3;c = 100;}

public override void doSomething()

{

System.Threading.Thread.Sleep(1000);

System.Console.WriteLine("\tvalues a={0}, b={1}, c={2}", a, b, c);

}

}

public class BEqualOtherClass : AEqual1Class

{

public BEqualOtherClass(){b = 100;c = 100;}

public override void doSomething()

{

System.Threading.Thread.Sleep(1000);

System.Console.WriteLine("\tvalues a={0}, b={1}, c={2}", a, b, c);

}

}

public class AEqualOtherClass : MyBaseClass

{

public AEqualOtherClass(){a = 100;b = 100;c = 100;}

public override void doSomething()

{

System.Threading.Thread.Sleep(1000);

System.Console.WriteLine("\tvalues a={0}, b={1}, c={2}",a,b,c);

}

}

}

Comments

  • Anonymous
    May 12, 2010
    It's very interesting. Would you please attach your test project into this post?

  • Anonymous
    May 12, 2010
    you got it Kevin, i've updated the article

  • Anonymous
    May 12, 2010
    The results are interesting, but really make perfect sense. For a=b=c=100, the "if" version would have to evaluate every single one of the various "if" statements before finally arriving at a doSomething. The "NoIf" version can go straight to the correct doSomething. Even for a=1, b=2, c=3, the number of statements being executed for both is very small, hence why both times are low. That said, what are the memory footprints of each version?

  • Anonymous
    May 12, 2010
    Not sure I'd want to write a class for each case though.

  • Anonymous
    May 13, 2010
    The comment has been removed

  • Anonymous
    May 15, 2010
    The comment has been removed

  • Anonymous
    June 01, 2010
    Quoting you: "Let’s take it step by step if i have two products A & B A comes in three flavors C, D & E. C comes in three flavors too F, G & H. so when you come to the bottom of it, you see that there are actually 6 products. C, D, E, F, G & H." Did you mean "B comes in three flavors too"?