The title really says it all. In VB.NET is there a difference between these statements when checking for value equality
Dim notEqualsCompare as Boolean = Not a = b
Dim angleBracCompare as Boolean = a <> b
I usually use 'Not a = b' just because it reads better.
I read the '<>' operator as 'is less or greater than' which only really makes sense for numeric values, but from my brief testing they behave the same.
Is there ever a situation where one is preferable?
In practice, they should always be functionally equivalent.
As mentioned in one of the other answers, Not a = b is logically two separate operations. You may trust that the compiler will optimize that for you, but, regardless, most programmers would agree that, if a language has an operator to do what you want, you should generally use that feature of the language rather than using multiple operations to accomplish the same result. If you don't like the language, choose another language. But if you're going to use VB, it's best to get used to it and take advantage of it's syntax.
Technically, though, it's worth mentioning that they aren't necessarily the same. All three of the following lines could technically have different results:
result = Not a = b
result = a <> b
result = Not a.Equals(b)
The reason why they can be different is because VB allows you to override the = operator (equality test, not assignment), the <> operator, the Not operator, and the Equals method. So, even though it would be horrendous to override those things and provide differing functionality for each, it is technically possible. For obvious reasons, the "official" guidelines from Microsoft recommend that they always work consistent to each other.
Consider:
Public Sub Main()
Dim a As New Crazy()
Dim b As New Crazy()
Console.WriteLine(a = b) ' False
Console.WriteLine(a.Equals(b)) ' True
Console.WriteLine(a <> b) ' False
Console.WriteLine(Not a) ' "Opposite"
Console.WriteLine(Not a = b) ' True
Console.WriteLine(Not a.Equals(b)) ' False
End Sub
Private Class Crazy
Public Shared Operator <>(x As Crazy, y As Crazy) As Boolean
Return False
End Operator
Public Shared Operator =(x As Crazy, y As Crazy) As Boolean
Return False
End Operator
Public Overrides Function Equals(obj As Object) As Boolean
Return True
End Function
Public Shared Operator Not(value As Crazy) As String
Return "Opposite"
End Operator
End Class
They both produce the same answer, however, a <> b would probably be more efficient. The reason being is that when the compiler comes to "Not a = b", the compiler must first do the comparison (a = b), then it must use clock cycles to flip that login (Not). When doing a <> b, the compiler would only have to do the comparison and then it's done. Look at this chart:
a <> b ' One Operation
c = a = b ' One Operation
Not c ' Another Operation
Related
This question already has answers here:
AndAlso/OrElse in VBA
(10 answers)
Closed 8 years ago.
VBA doesn't short-circuit
VBA does not support short-circuiting - apparently because it only has bitwise And/Or/Not etc operations. From the VBA language specification: "Logical operators are simple data operators that perform bitwise computations on their operands." In this light, it makes sense that VBA was designed with true = &H1111 and false = &H0000: this way logical statements can be evaluated as bitwise operations.
The lack of short-circuiting can cause problems
Performance: the ReallyExpensiveFunction() will always be run when this statement is evaluated, even if it is not necessary by the result of the left hand side of the condition
If IsNecessary() And ReallyExpensiveFunction() Then
'...
End If
Errors: if MyObj is Nothing, this conditional statment will result in a runtime error because VBA will still try to check the value of Property
If Not MyObj Is Nothing And MyObj.Property = 5 Then
'...
End If
The solution I've used to implement short-cirtcuiting behavior is nested Ifs
If cond1 And cond2 Then
'...
End If
Becomes
If cond1 Then
If cond2 Then
'...
End If
End If
This way the If statements give the short-circuit-like behavior of not bothering to evaluate cond2 if cond1 is False.
If there is an Else clause, this creates duplicate code blocks
If Not MyObj Is Nothing And MyObj.Property = 5 Then
MsgBox "YAY"
Else
MsgBox "BOO"
End If
Becomes
If Not MyObj Is Nothing Then
If MyObj.Property = 5 Then
MsgBox "YAY"
Else
MsgBox "BOO" 'Duplicate
End If
Else
MsgBox "BOO" 'Duplicate
End If
Is there a way to rewrite If statements to preserve the short-circuit behavior, but avoid duplication of code?
Perhaps with another branching statement like Select Case?
To add context to the question, here is the specific case I'm looking at. I'm implementing a hash table that handles collisions by chaining them in a linked list. The underlying array size is enforced to be a power of two and the hashes are distributed into the current array size by truncating them to the appropriate length.
For example, suppose the array length is 16 (binary 10000). If I have a key that hashes to 27 (binary 11011), I can store it in my 16 slot array by keeping only the bits within the limit of that array size. The index where this item would be stored is (hash value) And (length of array - 1) which in this case is (binary 11011) And (1111) which is 1011 which is 11. The actual hash code is stored along with the key in the slot.
When looking up an item in the hash table in a chain, both the hash and the key must be checked to determine that the correct item has been found. However, if the hash doesn't match, then there is no reason to check the key. I was hoping to gain some tiny intangible amount of performance by nesting the Ifs to get the short-circuit behavior:
While Not e Is Nothing
If keyhash = e.hash Then
If Key = e.Key Then
e.Value = Value
Exit Property
Else
Set e = e.nextEntry
End If
Else
Set e = e.nextEntry
End If
Wend
You can see the Set... is duplicated, and thus this question.
As a more general apprach, I suggest to introduce condition flags and make usage of assigning comparison results to booleans:
dim cond1 as boolean
dim cond2 as boolean
cond1 = false
cond2 = false
' Step 1
cond1 = MyObj Is Nothing
' Step 2: do it only if step 1 was sucessful
if cond1 then
cond2 = MyObj.Property = 5
end if
' Final result:
if cond2 then
msgbox "Yay"
else
msgbox "Boo"
end if
By "chaining" those condition flags, every step is safe, you see the final result in the last condition flag and you don't do unnecessary comparisons. And, to me, it keeps readable.
EDIT 2014-07-09
I usually never omit block delimiters and I consequently set every statement of control structures on a new line. But in this case, you can carefully get a very dense notation that reminds on short-circuit notation, also because the VBA compiler initiates the variables:
dim cond1 as boolean
dim cond2 as boolean
dim cond3 as boolean
dim cond4 as boolean
cond1 = MyObj Is Nothing
if cond1 then cond2 = MyObj.Property = 5
if cond2 then cond3 = MyObj.Property2 = constSomething
if cond3 then cond4 = not isNull(MyObj.Property77)
if cond4 then
msgbox "Hyper-Yay"
else
msgbox "Boo"
end if
I could agree to this. It's a clear flow to read.
EDIT 2021-03-21
Thanks to #Tom's comment, one can write it simpler:
dim cond as boolean
cond = MyObj Is Nothing
if cond then cond = MyObj.Property = 5
if cond then cond = MyObj.Property2 = constSomething
if cond then cond = not isNull(MyObj.Property77)
if cond then
msgbox "Hyper-Yay"
else
msgbox "Boo"
end if
#Tom explains the advantages in his comment below. I fully agree with this. I can only imagine some situations while debugging, when I would like to have separated results of the conditions, and therefore explicitely with four different variables.
There is a way. You're not guaranteed to like it. But this is one of those carefully constructed cases where Goto comes in handy
If Not MyObj Is Nothing Then
If MyObj.Property = 5 Then
MsgBox "YAY"
Else
Goto JUMPHERE
End If
Else
JUMPHERE:
MsgBox "BOO" 'Duplicate
End If
A short-circuited code to implement a short-circuited condition!
Alternately, if instead of MsgBox "BOO" is some long and convoluted code, it can be wrapped in a function and that can be written twice with minimal impact/overhead.
Regarding the specific use case, the multiple Set operations will have a minimal performance impact and hence, if one wants to avoid using Goto (still the most globally efficient approach, codesize + performance wise, avoiding creation of dummy variables, etc. - won't matter, though for such a small piece of code) there is negligible downside in simply repeating the command.
Just to analyze (your sample code) how much can be gained by different methods...
If both conditions are true:, there are 2 comparisons, 1 assignment, 0 jumps
If only first condition is true: there are 2 comparisons, 1 pointer-assignment, 1 jump
If only second condition is true: there is 1 comparison, 1 pointer-assignment, 1 jump
If both conditions are false: there is 1 comparison, 1 pointer-assignment, 1 jump (same as above)
In terms of performance, a jump is usually more expensive than comparison (which happens very quickly in ALU vs. the jump which could lead to a disruption in the code cache, maybe not at these sizes, but still jumps are expensive).
And normal assignment by value would be at best as fast as a pointer-assignment or sometimes worse (this is VBA, can't be 100% sure of the p-code implementation)
So, depending on your use case / expected data, you can try to minimize average number of jumps per iteration in your loop and reorder the code.
How about:
s = "BOO"
If Not MyObj Is Nothing Then
If MyObj.Property = 5 Then s = "YAY"
End If
MsgBox s
In VBA, you can treat a UDF name just like a Dimmed variable. For example
Function ADD(a, b) As Long
ADD = a
ADD = ADD + b
End Function
Where ADD stores the intermediate value as well as the end result. My question is; in terms of what's going on behind the scenes, is there any difference between storing a number/piece of data in a standard variable vs a function name variable.
I worry that perhaps the routine that called the function gets an update whenever the variable changes if you use the function name, rather than only when End Function is executed. IE. if you have some code
answer = ADD(1, 2)
then in memory answer gets written to twice, once when ADD = a, once when ADD = ADD + b. Of course we don't see this, because answer is left with whatever the final ADD value is
I ask because I often find I build up a function answer in stages using an intermediate variable, then pass that to the function name itself, where instead I could just write directly to the function name.
E.g.
Function ADD(a, b) As Long
Dim tot As Long
tot = a
tot = tot + b
ADD = tot
End Function
vs the first example. They acheive the same thing, in the second example tot represents the formula result, and so we need a final ADD = tot line at the end. For speed I would like to reduce any writes that are made, so is there any drawback in terms of speed, not readability to using the first method as opposed to declaring intermediates?
NB, to clarify, that's not all intermediates, I just mean the single intermediate that represents the function result, and could be replaced by the function name in the code.
In speed the first method should be slightly faster - you declare one variable less (but I doubt that someone would be able to notice it).
In general, using the first method can bring you to a recursion, if you are not careful (or if you are a VBA beginner):
Option Explicit
Dim lng10 As Long
Public Sub Test()
lng10 = 0
Debug.Print ADD2(1, 1)
End Sub
Function ADD2(a As Long, b As Long) As Long
lng10 = lng10 + 1
ADD2 = a + b
If lng10 < 10 Then
ADD2 = ADD2 + ADD2(1, 1)
End If
End Function
And if the recursion does not have a bottom, it would go to an overflow error.
With other words, this would be an runtime error:
Option Explicit
Dim lng10 As Long
Public Sub Test()
lng10 = 0
Debug.Print ADD2(1, 1)
End Sub
Function ADD2(a As Long, b As Long) As Long
lng10 = lng10 + 1
ADD2 = ADD2(a, b)
End Function
I need to check an array of booleans and for each value act accordingly.
Current code is something like this, but i want to make it read easier
If heater_check(0) = true Then
get_temp(0)
End If
If heater_check(1) = true Then
get_temp(1)
End If
...
And so on. Is there a better solution?
I guess this is what you are looking for
For i As Integer = 0 To heater_check.length - 1
If heater_check(i) then
get_temp(i)
End If
Next
"For a case like this, could a For loop still work? If node_num = "1" Then Temperature(0) = C_D(Convert.ToChar(raw_result(byte_num + 22))) + C_D(Convert.ToChar(raw_result(b........ "chia kang ren
And the answer :
"As long as there is a 'pattern' on your variable changes, you can always use loop to simplify your If-Else statement"TheQuickBrownFox
..or use some logic to tie together two variables of different types having some sort of relation between, whenever required.
' ...
Dim TempIndex As Int32 = Integer.Parse(node_num) - 1
' Converts node_num to an Integer and substract 1.
Temperature(TempIndex) = _
C_D(Convert.ToChar(raw_result(byte_num + 22))) + _
C_D(Convert.ToChar(raw_result(byte_num + 21))) * 16 + _
C_D(Convert.ToChar(raw_result(byte_num + 20))) * 256
' ...
By the way, if you're asking A, only answers to A are relevant, or answers that covers A and anything directly related to A like A', -A, A² or |A|.
Here I'm talking about converting a String to Integer. That has nothing to do with :
"I need to check an array of booleans and for each value act accordingly."
=> Please mark TheQuickBrownFox's answer as the valid answer. (And avoid asking other questions than the original one - :) )
This question already has answers here:
AndAlso/OrElse in VBA
(10 answers)
Closed 8 years ago.
VBA doesn't short-circuit
VBA does not support short-circuiting - apparently because it only has bitwise And/Or/Not etc operations. From the VBA language specification: "Logical operators are simple data operators that perform bitwise computations on their operands." In this light, it makes sense that VBA was designed with true = &H1111 and false = &H0000: this way logical statements can be evaluated as bitwise operations.
The lack of short-circuiting can cause problems
Performance: the ReallyExpensiveFunction() will always be run when this statement is evaluated, even if it is not necessary by the result of the left hand side of the condition
If IsNecessary() And ReallyExpensiveFunction() Then
'...
End If
Errors: if MyObj is Nothing, this conditional statment will result in a runtime error because VBA will still try to check the value of Property
If Not MyObj Is Nothing And MyObj.Property = 5 Then
'...
End If
The solution I've used to implement short-cirtcuiting behavior is nested Ifs
If cond1 And cond2 Then
'...
End If
Becomes
If cond1 Then
If cond2 Then
'...
End If
End If
This way the If statements give the short-circuit-like behavior of not bothering to evaluate cond2 if cond1 is False.
If there is an Else clause, this creates duplicate code blocks
If Not MyObj Is Nothing And MyObj.Property = 5 Then
MsgBox "YAY"
Else
MsgBox "BOO"
End If
Becomes
If Not MyObj Is Nothing Then
If MyObj.Property = 5 Then
MsgBox "YAY"
Else
MsgBox "BOO" 'Duplicate
End If
Else
MsgBox "BOO" 'Duplicate
End If
Is there a way to rewrite If statements to preserve the short-circuit behavior, but avoid duplication of code?
Perhaps with another branching statement like Select Case?
To add context to the question, here is the specific case I'm looking at. I'm implementing a hash table that handles collisions by chaining them in a linked list. The underlying array size is enforced to be a power of two and the hashes are distributed into the current array size by truncating them to the appropriate length.
For example, suppose the array length is 16 (binary 10000). If I have a key that hashes to 27 (binary 11011), I can store it in my 16 slot array by keeping only the bits within the limit of that array size. The index where this item would be stored is (hash value) And (length of array - 1) which in this case is (binary 11011) And (1111) which is 1011 which is 11. The actual hash code is stored along with the key in the slot.
When looking up an item in the hash table in a chain, both the hash and the key must be checked to determine that the correct item has been found. However, if the hash doesn't match, then there is no reason to check the key. I was hoping to gain some tiny intangible amount of performance by nesting the Ifs to get the short-circuit behavior:
While Not e Is Nothing
If keyhash = e.hash Then
If Key = e.Key Then
e.Value = Value
Exit Property
Else
Set e = e.nextEntry
End If
Else
Set e = e.nextEntry
End If
Wend
You can see the Set... is duplicated, and thus this question.
As a more general apprach, I suggest to introduce condition flags and make usage of assigning comparison results to booleans:
dim cond1 as boolean
dim cond2 as boolean
cond1 = false
cond2 = false
' Step 1
cond1 = MyObj Is Nothing
' Step 2: do it only if step 1 was sucessful
if cond1 then
cond2 = MyObj.Property = 5
end if
' Final result:
if cond2 then
msgbox "Yay"
else
msgbox "Boo"
end if
By "chaining" those condition flags, every step is safe, you see the final result in the last condition flag and you don't do unnecessary comparisons. And, to me, it keeps readable.
EDIT 2014-07-09
I usually never omit block delimiters and I consequently set every statement of control structures on a new line. But in this case, you can carefully get a very dense notation that reminds on short-circuit notation, also because the VBA compiler initiates the variables:
dim cond1 as boolean
dim cond2 as boolean
dim cond3 as boolean
dim cond4 as boolean
cond1 = MyObj Is Nothing
if cond1 then cond2 = MyObj.Property = 5
if cond2 then cond3 = MyObj.Property2 = constSomething
if cond3 then cond4 = not isNull(MyObj.Property77)
if cond4 then
msgbox "Hyper-Yay"
else
msgbox "Boo"
end if
I could agree to this. It's a clear flow to read.
EDIT 2021-03-21
Thanks to #Tom's comment, one can write it simpler:
dim cond as boolean
cond = MyObj Is Nothing
if cond then cond = MyObj.Property = 5
if cond then cond = MyObj.Property2 = constSomething
if cond then cond = not isNull(MyObj.Property77)
if cond then
msgbox "Hyper-Yay"
else
msgbox "Boo"
end if
#Tom explains the advantages in his comment below. I fully agree with this. I can only imagine some situations while debugging, when I would like to have separated results of the conditions, and therefore explicitely with four different variables.
There is a way. You're not guaranteed to like it. But this is one of those carefully constructed cases where Goto comes in handy
If Not MyObj Is Nothing Then
If MyObj.Property = 5 Then
MsgBox "YAY"
Else
Goto JUMPHERE
End If
Else
JUMPHERE:
MsgBox "BOO" 'Duplicate
End If
A short-circuited code to implement a short-circuited condition!
Alternately, if instead of MsgBox "BOO" is some long and convoluted code, it can be wrapped in a function and that can be written twice with minimal impact/overhead.
Regarding the specific use case, the multiple Set operations will have a minimal performance impact and hence, if one wants to avoid using Goto (still the most globally efficient approach, codesize + performance wise, avoiding creation of dummy variables, etc. - won't matter, though for such a small piece of code) there is negligible downside in simply repeating the command.
Just to analyze (your sample code) how much can be gained by different methods...
If both conditions are true:, there are 2 comparisons, 1 assignment, 0 jumps
If only first condition is true: there are 2 comparisons, 1 pointer-assignment, 1 jump
If only second condition is true: there is 1 comparison, 1 pointer-assignment, 1 jump
If both conditions are false: there is 1 comparison, 1 pointer-assignment, 1 jump (same as above)
In terms of performance, a jump is usually more expensive than comparison (which happens very quickly in ALU vs. the jump which could lead to a disruption in the code cache, maybe not at these sizes, but still jumps are expensive).
And normal assignment by value would be at best as fast as a pointer-assignment or sometimes worse (this is VBA, can't be 100% sure of the p-code implementation)
So, depending on your use case / expected data, you can try to minimize average number of jumps per iteration in your loop and reorder the code.
How about:
s = "BOO"
If Not MyObj Is Nothing Then
If MyObj.Property = 5 Then s = "YAY"
End If
MsgBox s
What is the difference between (OrElse and Or) and (AndAlso and And)?
Is there any difference in their performances, let say the correctness benefit?? Is there any situation that I shoudn't use OrElse and AndAlso?
Or/And will always evaluate both1 the expressions and then return a result. They are not short-circuiting.
OrElse/AndAlso are short-circuiting. The right expression is only evaluated if the outcome cannot be determined from the evaluation of the left expression alone. (That means: OrElse will only evaluate the right expression if the left expression is false, and AndAlso will only evaluate the right expression if the left expression is true.)
Assuming that no side effects occur in the expressions and the expressions are not dependent (and any execution overhead is ignored), then they are the same.
However, in many cases it is that the expressions are dependent. For instance, we want to do something when a List is not-Nothing and has more than one element:
If list IsNot Nothing AndAlso list.Length > 0 Then .. 'list has stuff
This can also be used to avoid an "expensive" computation (or side-effects, ick!):
If Not Validate(x) OrElse Not ExpensiveValidate(x) Then .. 'not valid
Personally, I find that AndAlso and OrElse are the correct operators to use in all but the 1% - or less, hopefully! - of the cases where a side-effect is desired.
Happy coding.
1 An Exception thrown in the first expression will prevent the second expression from being evaluated, but this should hardly be surprising ..
Besides the short-circuiting mentioned in the other answers, Or/And are usable as bitwise operators where OrElse/AndAlso are not. Bitwise operations include combining values of Flags enums, such as the FileAttributes enumeration where you might indicate a file is both read only and hidden by FileAttributes.ReadOnly Or FileAttributes.Hidden
The difference is that OrElse and AndAlso will short-circuit based on the first condition, meaning that if the first condition doesn't pass, the second (or more) conditions will not be evaluated. This is particularly useful when one of the conditions might be more intensive than the other.
Example where Or is fine (both conditions evaluated):
If Name = "Fred" Or Name = "Sam" Then
It really doesn't matter which way around they are evaluated
The following AndAlso is useful because the second condition might fail
If Not SomeObject Is Nothing AndAlso CheckObjectExistsInDatabase(SomeObject) Then
This allows for the first condition to check whether the object has been set and only if it has been set will go and check the database (or some other task). If this had been a plain And keyword, both would be evaluated.
#Gideon - glad someone pointed that out. Here is a simple test that shows the dramatic impact of AndAlso:
Dim tm As New Stopwatch
Const tries As Integer = 123456
Dim z As Integer = 0
Dim s() As String = New String() {"0", "one"}
Debug.WriteLine("AndAlso")
For x As Integer = 0 To s.Length - 1
z = 0
tm.Restart() 'restart the stopwatch
For y As Integer = 0 To tries
If s(x) = x.ToString AndAlso s(x) = y.ToString Then '<<<<<<<<<<
z += 1
End If
Next
tm.Stop()
Debug.WriteLine(x.ToString.PadRight(3, " "c) & z.ToString.PadRight(10, " "c) & tm.Elapsed.ToString)
Next
Debug.WriteLine("And")
For x As Integer = 0 To s.Length - 1
z = 0
tm.Restart() 'restart the stopwatch
For y As Integer = 0 To tries
If s(x) = x.ToString And s(x) = y.ToString Then '<<<<<<<<<<
z += 1
End If
Next
tm.Stop()
Debug.WriteLine(x.ToString.PadRight(3, " "c) & z.ToString.PadRight(10, " "c) & tm.Elapsed.ToString)
Next