Is there any situation where Or is better to use than OrElse?
If not, why don't they just "upgrade" the internal code?
The only reason to use Or is when you want bitwise arithmetic, i.e. you want to manipulate the bits in a number:
Sub SetBit(value As Integer, Bit As Integer)
value = value Or (1 << Bit)
End Sub
This kind is the only case appropriate for Or. In all other cases (i.e. when using Boolean logic), use OrElse.
Despite their similar names, Or and OrElse are semantically quite distinct operations which should not be confused with each other. It just so happens to be that the internal representation of Booleans makes it possible to use bitwise Or to achieve a similar (but not the same) effect to OrElse. (Old versions of BASIC and VB – before .NET – exploited this relationship by only providing an Or operation, no OrElse.)
You should always use OrElse instead of Or, except when doing bit-wise arithmetic.
OrElse is a short-circuiting comparison, meaning it will not evaluate the second clause if the first was true. This is extremely useful, because you will often want clauses which could fail without shortcircuiting (eg. x is nothing OrElse not x.HasSomeProperty).
The reason it is not possible to automatically upgrade all 'Or's as 'OrElse's is because the evaluation of the second clause may be important. For example, I could write "True Or SomeBooleanMethodWhichMightThrowAnEception()". Changing that Or to an OrElse would change the meaning of the program.
Edit: This code is evil; I merely added this answer to indicate that this is possible.
Another case would be to use Or when evaluating expressions that perform some sort of side effect that must occur:
Sub DoSomething()
Dim succeeded As Boolean
succeeded = FirstThing() Or SecondThing() Or ThirdThing()
If succeeded Then
' Do something here
End If
End Sub
In this case FirstThing, SecondThing, and ThirdThing are methods that must be executed as a whole whether any of them fail or not, while accumulating a success value. If you used OrElse then if FirstThing or SecondThing fail, then the operations behind the failing method wouldn't occur.
Related
I always use AndAlso while checking multiple conditions as it doesn't evaluate right side unless left one is true. I don't see any situation where someone would like to evaluate right side even if left one fails. If it was needed then why they didn't include same in C#.
Update:
As accepted answer pointed out that it exists because it is used for bitwise operation, that fine enough but I still think they would have overloaded And operator to serve both purposes and just not created AndAlso. If anyone can pour some light on it, this question is still open :)
They included the same in C#. In C# you can use & (And) or && (AndAlso).
There's no real use case i can imagine for the not short-circuit operator when comparing booleans, but And can be used with numeric values, and it then does a bitwise comparison. That's why it exists. But when comparing boolean types, you'll always be using the short-circuit version.
And is also a bit operator. Here is an example showing a mix of And an AndAlso.
Dim foo? As Integer = 5
If foo.HasValue AndAlso (foo And 1) = 1 AndAlso (foo And 4) = 4 Then
Stop
End If
The large majority of SonarLint rules that I've come across in Java seemed plausible and justified. However, ever since I've started using SonarLint for VB.NET, I've come across several rules that left me questioning their usefulness or even whether or not they are working correctly.
I'd like to know if this is simply a problem of me using some VB.NET constructs in a suboptimal way or whether the rule really is flawed.
(Apologies if this question is a little longer. I didn't know if I should create a separate question for each individual rule.)
The following rules I found to leave some cases unconsidered that would actually turn up as false-positives:
S1871: Two branches in the same conditional structure should not have exactly the same implementation
I found this one to bring up a lot of false-positives for me, because sometimes the order in which the conditions are checked actually does matter. Take the following pseudo code as example:
If conditionA() Then
doSomething()
ElseIf conditionB() AndAlso conditionC() Then
doSomethingElse()
ElseIf conditionD() OrElse conditionE() Then
doYetAnotherThing()
'... feel free to have even more cases in between here
Else Then
doSomething() 'Non-compliant
End If
If I wanted to follow this Sonar rule and still make the code behave the same way, I'd have to add the negated version of each ElseIf-condition to the first If-condition.
Another example would be the following switch:
Select Case i
Case 0 To 40
value = 0
Case 41 To 60
value = 1
Case 61 To 80
value = 3
Case 81 To 100
value = 5
Case Else
value = 0 'Non-compliant
There shouldn't be anything wrong with having that last case in a switch. True, I could have initialized value beforehand to 0 and ignored that last case, but then I'd have one more assignment operation than necessary. And the Java ruleset has conditioned me to always put a default case in every switch.
S1764: Identical expressions should not be used on both sides of a binary operator
This rule does not seem to take into account that some functions may return different values every time you call them, for instance collections where accessing an element removes it from the collection:
stack.Push(stack.Pop() / stack.Pop()) 'Non-compliant
I understand if this is too much of an edge case to make special exceptions for it, though.
The following rules I am not actually sure about:
S3385: "Exit" statements should not be used
While I agree that Return is more readable than Exit Sub, is it really bad to use a single Exit For to break out of a For or a For Each loop? The SonarLint rule for Java permits the use of a single break; in a loop before flagging it as an issue. Is there a reason why the default in VB.NET is more strict in that regard? Or is the rule built on the assumption that you can solve nearly all your loop problems with LINQ extension methods and lambdas?
S2374: Signed types should be preferred to unsigned ones
This rule basically states that unsigned types should not be used at all because they "have different arithmetic operators than signed ones - operators that few developers understand". In my code I am only using UInteger for ID values (because I don't need negative values and a Long would be a waste of memory in my case). They are stored in List(Of UInteger) and only ever compared to other UIntegers. Is this rule even relevant to my case (are comparisons part of these "arithmetic operators" mentioned by the rule) and what exactly would be the pitfall? And if not, wouldn't it be better to make that rule apply to arithmetic operations involving unsigned types, rather than their declaration?
S2355: Array literals should be used instead of array creation expressions
Maybe I don't know VB.NET well enough, but how exactly would I satisfy this rule in the following case where I want to create a fixed-size array where the initialization length is only known at runtime? Is this a false-positive?
Dim myObjects As Object() = New Object(someOtherList.Count - 3) {} 'Non-compliant
Sure, I could probably just use a List(Of Object). But I am curious anyway.
Thanks for raising these points. Note that not all rules apply every time. There are cases when we need to balance between false positives/false negatives/real cases. For example with identical expressions on both sides of an operator rule. Is it a bug to have the same operands? No it's not. If it was, then the compiler would report it. Is it a bad smell, is it usually a mistake? Yes in many cases. See this for example in Roslyn. Should we tune this rule to exclude some cases? Yes we should, there's nothing wrong with 2 << 2. So there's a lot of balancing that needs to happen, and we try to settle for an implementation that brings the most value for the users.
For the points you raised:
Two branches in the same conditional structure should not have exactly the same implementation
This rule generally states that having two blocks of code match exactly is a bad sign. Copy-pasted code should be avoided for many reasons, for example if you need to fix the code in one place, you'll need to fix it in the other too. You're right that adding negated conditions would be a mess, but if you extract each condition into its own method (and call the negated methods inside them) with proper names, then it would probably improves the readability of your code.
For the Select Case, again, copy pasted code is always a bad sign. In this case you could do this:
Select Case i
...
Case 0 To 40
Case Else
value = 0 ' Compliant
End Select
Or simply remove the 0-40 case.
Identical expressions should not be used on both sides of a binary operator
I think this is a corner case. See the first paragraph of the answer.
"Exit" statements should not be used
It's almost always true that by choosing another type of loop, or changing the stop condition, you can get away without using any "Exit" statements. It's good practice to have a single exit point from loops.
Signed types should be preferred to unsigned ones
This is a legacy rule from SonarQube VB.NET, and I agree with you that it shouldn't be enabled by default in SonarLint. I created the following ticket in our JIRA: https://jira.sonarsource.com/browse/SLVS-1074
Array literals should be used instead of array creation expressions
Yes, it seems to be a false positive, we shouldn't report on array creations when the size is explicitly specified. https://jira.sonarsource.com/browse/SLVS-1075
Today I was working an in-class project with my students when I ran into this bug.
Imgur Link
Pastebin Link
Basically, decTemperature is a String variable that receives an input from the User. In order to teach data validation, short-circuiting, and loops, we were using the following While loop condtionals to force a valid response:
While IsNumeric(decTemperature) = False Or
Convert.ToDecimal(decTemperature) <= 0.0 Or
Convert.ToDecimal(decTemperature) > 135.0
If the user puts in 'abc', in theory the conditional statement should short circuit before reaching the second part of the conditional statement. I attempted the conditional a number of different ways, but ultimately it would crash in every design.
My assumption on the issue probably links closely to an older question I asked about dealing with data types with explicitly setting Option Strict 'on' (although a quick add of Option Strict On in the above code still crashes). That is to say, decTemperature is being processed in each conditional statement before evaluating.
Whatever the case, what is causing the issue and what would be a better approach that still maintains the concepts (that is forcing a valid response from the user)? I have an idea with using a Boolean data type validResponse and setting it, but that seems to be throwing away short-circuiting as a concept.
Or does not short-circuit. Neither does And
OrElse does short-circuit (as well as AndAlso). See OrElse Operator (Visual Basic)
So it should look like this:
While IsNumeric(decTemperature) = False OrElse _
(Convert.ToDecimal(decTemperature) <= 0.0 OrElse _
Convert.ToDecimal(decTemperature) > 135.0)
I would consider using Decimal.TryParse to test the validity of the input.
If you just use Or then every statement is evaluated in every case. That's what the short circuit operators OrElse and AndAlso are for. If you use OrElse the If statement stops the evaluation after the first true statement is detected (or the first false statement in case of an AndAlso).
So in your case the conversion to decimal would be executed in any case. This is avoided with the short circuit operators.
In VB.NET, there's no == operator for comparison, so the = operator serves that purpose as well as assignment. I have a function, and I want it to return the boolean result of a comparison, without storing that result in a variable:
Private Function foo() As Boolean
Dim bar As Integer = 1
Return bar = 2
End Function
Returns: False
OK, but what's the value of bar?
Private Function foo() As KeyValuePair(Of Boolean, Integer)
Dim bar As Integer = 1
Return New KeyValuePair(Of Boolean, Integer)(bar = 2, bar)
End Function
Returns: False, 1
It looks like = will perform a comparison when the statement context demands it, but is this guaranteed? That is, can I be sure that bar will never be set to 2 in this situation?
Also, I know that VB.NET doesn't allow chained inline assignments, which may be for the best. Does this odd = behavior cause any other quirks I should be aware of?
You cannot do in-line assignments in VB, Assignment is an explicit statement:
[Let] <<target-reference>> = <<value-expression>>
The Let is optional and implicit, and hardly ever used anymore. The general rule that you can use to distinguish the [Let] command from equality testing is that for Let, no other keyword may come before the target-reference in the statement. AFAIK, in all cases of = as equality testing, there is one or more other keywords that precede it in the statement.
In your first example, the keyword Return precedes your =, so it's an equality test, and not an assignment.
In your first example you can do either:
Return 2
or
bar = 2
Return bar
As for your question "OK, but what's the value of bar?", bar still equals one.
= in VB cause no quirks. It works exactly as documented, and it always has (including its predecessor, BASIC back to 1968).
If you are starting to code in VB (coming from a language like C#), you should start getting used to the peculiar VB way of doing things; which is based on the idea: as simple and intuitive for the programmer as possible. "If assignation and comparison happen always in different contexts, why not using the same operator and let the context define its exact meaning?" -> VB-way of seeing things. "No, different realities have to be accounted for by different operators. End of the discussion" -> C#-way. :)
Is this reliable? Can you blindly trust on these not-always-clear-for-a-programmer bits? Sure, VB.NET peculiarities are highly-reliable and trustworthy. You can always use = (or Is on some contexts, but VS would tell you) and be completely sure that the code will do what is expected. But the question is: are you sure that you write exactly what you want?
This last question is what, perhaps, is more criticable of VB and what might give some problems to programmers from other languages: the higher the flexibility, the more likely is that you make an error; mainly if you are used to a different format.
Regarding the chained inline assignments, I honestly don't see its true utility (and never use them in C#). Regarding other differences with respect to C#, there are plenty of them; in some cases, I think that the C# approach is better; other times, the VB.NET one. On readability/length of code, I can refer to the With Statement I have always found somehow useful which is not present in C#.
One way to have 100% sure that the expression will be evaluated as an boolean expression is to use ()
e.g
Dim a = 2
Return (a = 1)
Since you cannot set a value to a variable wihtin the parenthesis.
What i want to say is: on an return statament for example you cant assing a value to a variable so, even if you use
a = 1
The compilator knows that this expression only can be an boolean expression.
The same to the if statament and so on..
Heh back in QB45 days we used to exploit the fact that "True" was the numeric value -1. So you would see code like x = 1 - x * (x < 6) (translation: increment x, but reset to 1 when it gets to 6)
When writing an If statement, I've always used And when needed like:
If 1=1 And 2=2 Then
The only time I ever used AndAlso is if the second condition will error if the first isnt true like:
If Not IsDbNull(Value) AndAlso Value=2 Then
However, recently I've heard that AndAlso is better for performance than And as the second condition is only read when the first is true.
In this case, should I always just use AndAlso?
Yes, AndAlso can be faster than And, because it doesn't evaluate subsequent conditions if an earlier condition proves false.
And is a throwback to earlier versions of Visual Basic.
Most (I hesitate to say all) modern languages use boolean operators that short-circuit conditions that don't strictly need to be evaluated.
e.g. && the and operator for C style languages all perform as AndAlso.
Be careful if you've lots of code that use And and Or, a global search and replace can change existing behaviour, if the second condition involves a function call that has side effects.
I would prefer using AndAlso and OrElse unless you specifically require the functionality provided by And & Or
Coming from a C and C++ background into VB (V5 initially) it was always really annoying that VB's and and or didn't short circuit. So the case where the second expression was dependent on the first was always harder to write.
I wouldn't expect to see much of a performance increase most of the time, unless the second expression has significant overhead, short circuiting operators will avoid executing it and thus speeding things up.
But if that second expression is a significant overhead then I would be concerned about side effects which will only be performed sometimes—this will make future maintenance harder and could make correctness harder to maintain.
When the conditions are also functions:
If functionA() And functionB() Then
...
public shared functionA() As Boolean
IF A is false THEN log -> return true or false
...
public shared functionB() As Boolean
IF B is false THEN log -> return true or false
Using AndAlso here could be the wrong way to go, because then it will only log B when both A and B are false.