Nicholas Post
Nicholas Post

Reputation: 1857

Performance Differences of Nested If Else Statements vs. ElseIf Statements

A coworker and I have differing opinions on If statements and their performance. My view is that If...ElseIf statements should be used. His view is that he doesn't believe in ElseIf, and writes everything with nested If statements.

Let's assume that a case statement cannot be used in this situation. What I am wondering is how efficiently code will be executed using nested If..Else statements versus using If...ElseIf statements. I know that code readability is a factor, but that shouldn't' affect performance.

Lets look at the following examples.

Using If Else:

If () then
    'Do something'
Else
    If () then
        'Do something'
    Else
        If () then
            'Do something'
        Else
            If () then
                'Do something'
            Else
                'Do something else'
            End If
        End If
    End If
End If

Using ElseIf:

If () then
    'Do something'
ElseIf () then
    'Do something'
ElseIf () then
    'Do something'
ElseIf () then
    'Do something'
Else
    'Do something else'
End If

I know this is a small scale example, but lets say blocks like this are used heavily throughout the application.

Are there any performance differences between the two code sections, or would they perform almost identically once the application is compiled?

####UPDATE#####

I created a program to test running through the functions x number of times.

Public Class Form1

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    For i As Integer = 0 To 1000
        Run()
    Next
End Sub

Sub Run()

    Dim Time1Start As Integer = 0
    Dim Time1End As Integer = 0
    Dim Time2Start As Integer = 0
    Dim Time2End As Integer = 0

    Time2Start = CInt(DateTime.Now.ToString("fff"))
    runElse()
    Time2End = CInt(DateTime.Now.ToString("fff"))

    Time1Start = CInt(DateTime.Now.ToString("fff"))
    runElseIf()
    Time1End = CInt(DateTime.Now.ToString("fff"))

    TextBox1.Text += If(Time1End < Time1Start, Time1End + (1000 - Time1Start), Time1End - Time1Start) & vbTab & If(Time2End < Time2Start, Time2End + (1000 - Time2Start), Time2End - Time2Start) & vbCrLf
End Sub

Sub runElseIf()
    If sleep(10) Then
        'Do something'
    Else
        If sleep(10) Then
            'Do something'
        Else
            If sleep(10) Then
                'Do something'
            Else
                If sleep(10) Then
                    'Do something'
                Else
                    If sleep(10) Then
                        'Do something'
                    Else
                        If sleep(10) Then
                            'Do something'
                        Else
                            If sleep(10) Then
                                'Do something'
                            Else
                                If sleep(10) Then
                                    'Do something'
                                Else
                                    If sleep(10) Then
                                        'Do something'
                                    Else
                                        If sleep(10) Then
                                            'Do something'
                                        Else
                                            'Do something else'
                                        End If
                                    End If
                                End If
                            End If
                        End If
                    End If
                End If
            End If
        End If
    End If
End Sub

Sub runElse()
    If sleep(10) Then
        'Do something'
    ElseIf sleep(10) Then
        'Do something'
    ElseIf sleep(10) Then
        'Do something'
    ElseIf sleep(10) Then
        'Do something'
    ElseIf sleep(10) Then
        'Do something'
    ElseIf sleep(10) Then
        'Do something'
    ElseIf sleep(10) Then
        'Do something'
    ElseIf sleep(10) Then
        'Do something'
    ElseIf sleep(10) Then
        'Do something'
    ElseIf sleep(10) Then
        'Do something'
    Else
        'Do something else'
    End If
End Sub

Function sleep(ByVal ms As Integer) As Integer
    System.Threading.Thread.Sleep(ms)
    Return False
End Function

End Class

I ran the program and here are my results:
500 Loops Average - ElseIf: 108.248ms If Else: 106.507ms
1000 Loops Average - ElseIf: 107.747ms If Else: 107.451ms (Else If running first)
1000 Loops Average - ElseIf: 107.683ms If Else: 107.076ms (ElseIf running first)

Perhaps with a larger data set the numbers would change, but out of those 3 trials it actually appears that the If Else is outperforming the ElseIf statements.

Upvotes: 6

Views: 10515

Answers (7)

James Lawruk
James Lawruk

Reputation: 31345

I ran a quick test and found that ElseIf runs slightly faster than Nested If. See the code below.

Imports System.Diagnostics
Module Module1

    Sub Main()
        Dim sw As New Stopwatch()
        Dim nestedTotal As Integer
        sw.Start()
        For i = 1 To 100000
            Nested()
        Next
        sw.Stop()
        nestedTotal = sw.ElapsedMilliseconds

        sw.Reset()

        Dim elsesTotal As Integer
        sw.Start()
        For i = 1 To 100000
            Elses()
        Next
        sw.Stop()
        elsesTotal = sw.ElapsedMilliseconds
        Console.WriteLine("Nested If:" & nestedTotal)
        Console.WriteLine("ElseIf:" & elsesTotal)
        Console.Read()
    End Sub

    Sub Nested()
        Dim num As Integer = GetNum()
        If num = 1 Then
            DoSomething()
        Else
            If num = 2 Then
                DoSomething()
            Else
                If num = 3 Then
                    DoSomething()
                Else
                    If num = 4 Then
                        DoSomething()
                    Else
                        DoSomething()
                    End If
                End If
            End If
        End If
    End Sub

    Sub DoSomething()
        Dim j As Integer
        For i = 1 To 1000
            j = i + j
        Next
    End Sub

    Sub Elses()
        Dim num As Integer = GetNum()
        If num = 1 Then
            DoSomething()
        ElseIf num = 2 Then
            DoSomething()
        ElseIf num = 3 Then
            DoSomething()
        ElseIf num = 4 Then
            DoSomething()
        Else
            DoSomething()
        End If
    End Sub

    Function GetNum()
        Dim Generator As System.Random = New System.Random()
        Return Generator.Next(1, 5)
    End Function
End Module

Upvotes: 0

the_lotus
the_lotus

Reputation: 12748

I've decompiled the two and it seem to be generating the same code (using ildasm). This is a very simple If statment, might get different result for different If. I would suggest you do the same with your code and see.

Module Module1

    Sub Main()

        Dim a As Integer
        Dim i As Integer = 1

        If i = 1 Then
            a = 9
        ElseIf i = 2 Then
            a = 8
        ElseIf i = 3 Then
            a = 7
        Else
            a = 6
        End If

    End Sub

End Module



.method public static void  Main() cil managed
{
  .entrypoint
  .custom instance void [mscorlib]System.STAThreadAttribute::.ctor() = ( 01 00 00 00 ) 
  // Code size       30 (0x1e)
  .maxstack  2
  .locals init ([0] int32 a,
           [1] int32 i)
  IL_0000:  ldc.i4.1
  IL_0001:  stloc.1
  IL_0002:  ldloc.1
  IL_0003:  ldc.i4.1
  IL_0004:  bne.un.s   IL_000b
  IL_0006:  ldc.i4.s   9
  IL_0008:  stloc.0
  IL_0009:  br.s       IL_001d
  IL_000b:  ldloc.1
  IL_000c:  ldc.i4.2
  IL_000d:  bne.un.s   IL_0013
  IL_000f:  ldc.i4.8
  IL_0010:  stloc.0
  IL_0011:  br.s       IL_001d
  IL_0013:  ldloc.1
  IL_0014:  ldc.i4.3
  IL_0015:  bne.un.s   IL_001b
  IL_0017:  ldc.i4.7
  IL_0018:  stloc.0
  IL_0019:  br.s       IL_001d
  IL_001b:  ldc.i4.6
  IL_001c:  stloc.0
  IL_001d:  ret
} // end of method Module1::Main

And the other one

Module Module1

    Sub Main()

        Dim a As Integer
        Dim i As Integer = 1

        If i = 1 Then
            a = 9
        Else
            If i = 2 Then
                a = 8
            Else
                If i = 3 Then
                    a = 7
                Else
                    a = 6
                End If
            End If
        End If

    End Sub

End Module

.method public static void  Main() cil managed
{
  .entrypoint
  .custom instance void [mscorlib]System.STAThreadAttribute::.ctor() = ( 01 00 00 00 ) 
  // Code size       30 (0x1e)
  .maxstack  2
  .locals init ([0] int32 a,
           [1] int32 i)
  IL_0000:  ldc.i4.1
  IL_0001:  stloc.1
  IL_0002:  ldloc.1
  IL_0003:  ldc.i4.1
  IL_0004:  bne.un.s   IL_000b
  IL_0006:  ldc.i4.s   9
  IL_0008:  stloc.0
  IL_0009:  br.s       IL_001d
  IL_000b:  ldloc.1
  IL_000c:  ldc.i4.2
  IL_000d:  bne.un.s   IL_0013
  IL_000f:  ldc.i4.8
  IL_0010:  stloc.0
  IL_0011:  br.s       IL_001d
  IL_0013:  ldloc.1
  IL_0014:  ldc.i4.3
  IL_0015:  bne.un.s   IL_001b
  IL_0017:  ldc.i4.7
  IL_0018:  stloc.0
  IL_0019:  br.s       IL_001d
  IL_001b:  ldc.i4.6
  IL_001c:  stloc.0
  IL_001d:  ret
} // end of method Module1::Main

I would suggest to use the one that is easier to read.

Upvotes: 8

dbasnett
dbasnett

Reputation: 11773

From a performance perspective there is no meaningful difference. For me the readability of the ElseIf is clearly better.

Private Sub xelseif(tries As Integer)
    Dim foo As Integer
    For x As Integer = 1 To tries
        For y As Integer = 1 To 5 Step 4
            If y = 1 Then
                foo = y
            ElseIf y = 2 Then
            ElseIf y = 3 Then
            ElseIf y = 4 Then
            ElseIf y = 5 Then
                foo = y
            End If
        Next
    Next
End Sub

Private Sub xelse(tries As Integer)
    Dim foo As Integer
    For x As Integer = 1 To tries
        For y As Integer = 1 To 5 Step 4
            If y = 1 Then
                foo = y
            Else
                If y = 2 Then
                Else
                    If y = 3 Then
                    Else
                        If y = 4 Then
                        Else
                            If y = 5 Then
                                foo = y
                            End If
                        End If
                    End If
                End If
            End If
        Next
    Next
End Sub

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    Dim stpw As New Stopwatch
    Dim tries As Integer = 1500000

    xelse(10)
    stpw.Restart()
    xelse(tries)
    stpw.Stop()
    Debug.WriteLine(stpw.ElapsedMilliseconds)

    xelseif(10)
    stpw.Restart()
    xelseif(tries)
    stpw.Stop()
    Debug.WriteLine(stpw.ElapsedMilliseconds)
End Sub

Upvotes: 0

STW
STW

Reputation: 46366

You're worrying about the wrong things!!!

The code you write isn't the code that is executed. The compiler will modify the structure of your code for optimization, and it does very well with things such as this. That said, even if it didn't perform optimizations the speed difference wouldn't matter.

Don't worry about "is it as fast as it can be?" Instead worry about "is it fast enough, and as maintainable (readable) as it can be?".

Compilers and processors are very good at understanding logic structures, but meatbags (people) aren't. Whenever you write code you should try to make sure that it's as approachable and readable as possible. If you find that it's unacceptible slow then you can begin sacrificing readability for performance--but doing so out of paranoia is called "premature optimization", and it's a great way to make code that will be unmaintainable (and eventually spawn bugs).

With that said, here's some guidelines:

  • Methods with many ifs/elses are a code-smell (they have a high "cyclomatic complexity". It indicates that a single method does many this, which makes it hard to read, maintain, test, and alter. Decompose your method into many smaller methods. You may still end up with a relatively large "control" method, which determines what to do--but delegate the task of actually doing it to other methods.

  • Reduce nesting as much as possible.

    If there are cases that result in a simple return or exit then try to check them early in the sequence: (e.g. if (something) { return; }).

  • Group related checks together, and try to refactor them to their own method

  • Cover it all extensively in tests

Upvotes: 7

plalx
plalx

Reputation: 43718

Well, I believe that it would all depend on the conditions you are checking.

For example (pseudo-code):

if (A && B) {
} elseif (A && C) {
} elseif (A && D) {
}

In this example, there's a common condition shared between all if statements, which means that re-writing to the following is probably more efficient:

if (A) {
    if (B) {
    } elseif (C) {
    } elseif (D) {
    }
}

However, if you cache the result of the A condition. The performance gains would probably minimal. Perhaps there are even optimizations performed by the compiler, so you would have to run a performance test to make sure there's even a difference in execution time.

More importantly, unless you are writing some performance-critical code, always try to write code by focusing on readability. There's almost always an efficient way of flattening conditionnal statements without hurting efficiency anyway.

Upvotes: 2

No Idea For Name
No Idea For Name

Reputation: 11577

i always prefer switch case when i have that many if elseif, but i know it's always possible. in that case the ElseIf always looks better, and is implemented in the background with else if, so it's should be the same performances.

but! for a lot of people, including some of my co-workers and bosses, it is not readable because the read it as if if if. i know it's crazy but it's some psychology thing i think.... so i understand where your coworker coming from

Upvotes: 0

Sasidharan
Sasidharan

Reputation: 3740

It depends on your code.

The if statement is only accessed when a condition is met, otherwise it is ignored. the if elseif else block is the same but it is testing for many conditions and depending on which one is met a different action might have to be performed in order to get the results u want.

My opinion is "It depends upon cases".

If you want to execute everything in your code,then use elseif..

if you want to ignore something use if..

Upvotes: 0

Related Questions