Reputation: 1857
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
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
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
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
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
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
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
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