Omitting "Case" from "Select...Case" Statement - vb.net

This isn't really a problem, but more of a curiosity of mine that I haven't been able to resolve by my own means. I surely won't be losing any sleep over it.
In VB.NET, the switch statement syntax is (as documented on MSDN here):
Select [ Case ] testexpression
[ Case expressionlist
[ statements ] ]
[ Case Else
[ elsestatements ] ]
End Select
Note that in the first line, Case is in square brackets, meaning that it is optional.
And indeed, the following example compiles and executes in the same way as if the Case keyword had been included, at least, in the rudimentary examples I've tried:
Select myIntVar
Case 0
Return "Nothing"
Case 1
Return "Just one"
Case Else
Return "Something else"
End Select
Therefore my question is as follows:
Aside from syntax, is there any difference between opening a switch statement with Select and Select Case?

I did a small experiment. I made up a small console application like so:
Module Module1
Sub Main()
Dim myStr As String = GetString(1)
End Sub
Private Function GetString(myIntVar) As String
Select myIntVar
Case 0
Return "Nothing"
Case 1
Return "Just one"
Case Else
Return "Something else"
End Select
End Function
End Module
The first run was as pictured above, and then I compiled it again inserting the Case keyword. I disassembled both created executables using ILDasm and pasted the IL of the GetString function into this online diff site: http://www.diffchecker.com/9ef7z423
Looks to me like Select Case and plain old Select are purely syntax differences (this is of course excluding the usage of Select in LINQ queries).

I would say there is no difference between the two forms. However, my only evidence is by way of an absence of drawing any distinction. Rather than looking at the Language Reference, the definitive place to look is in the Language Specification1.
In Version 11, under section 10.8.2, the Select Case statement is discussed, and the syntax shown is:
SelectStatement ::=
Select [ Case ] Expression StatementTerminator
[ CaseStatement+ ]
[ CaseElseStatement ]
End Select StatementTerminator
So, it's clear that this section does cover both forms. However, in the preceding 5 paragraphs (the entirety of the specification for Select Case Statements) no distinction is drawn between the two forms.
1The Reference tries to be descriptive, give examples, and uses (at times) looser language. The Specification should be followable to create a Visual Basic compiler. If something is missing from the former, then it may just be an omission. If something is missing from the latter, then it's not officially part of the language.

I think this comes from VB 6.0 where Select Case was mandatory - Select wasn't a statement on its own. This would mean that it's now just down to personal preference in VB.NET.
Edit: Strangely, if you do choose to omit it, Visual Studio will add it automatically.

Maybe it's just a difference in syntax, in terms of between languages, such as VB and C#
a switch statement requires the keyword break in order to break out of the loop.
Can't think of anything major, in terms of differences... sorry.

Related

SonarLint - questions about some of the rules for VB.NET

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

Understanding T-SQL GOTO

My teacher recently talked about the statement 'GOTO', to be used in Management Studio, but I didn't quite understand it at first. He stated that GOTO is being used to jump to different pieces of code, with the help of a label I can name by myself. This is the code he used to represent his example:
select 'first'
goto jump
select 'second'
jump:
select 'third'
When I execute the code, sure enough, it prints 'first' and 'third'. My question now is what was the select 'second' doing there in the first place?
In your example, the second select is clearly unnecessary.
GOTO is an example of "control-flow" for the the program code. It is a construct from the earliest computer languages, one that maps directly onto how the hardware works when processing languages such as C or assembly code. Since then, it has been included in many other languages.
GOTO would often be used with IF. However, T-SQL offers better control flow functionality, such as:
WHILE
IF/BEGIN
TRY/CATCH
In general, you should be using these constructs and not GOTO. In fact, GOTO is rather controversial. Many people think it is always a sign of poor code ("spaghetti code" is sometimes used to describe this type of code). Others will make a very rare exception for something like exception handling (which I sometimes do) or some types of state machines.
In my opinion, GOTO should only be taught after all the other constructs and only for very specific purposes.

Use String for IF statement conditions

I'm hoping someone can help answer my question, perhaps with an idea of where to go or whether what I'm trying to do is not possible with the way I want to do it.
I've been asked to write a set of rules based on the data held by our ERP form components or variables.
Unfortunately, these components and variables cannot be accessed or used outside of the ERP, so I can't use SQL to query the values and then build some kind of SQL query.
They'd like the ability to put statements like these:
C(MyComponentName) = C(MyOtherComponentName)
V(MyVariableName) > 16
(C(MyComponentName) = "") AND V(MyVariableName) <> "")
((C(MyComponentName) = "") OR C(MyOtherComponentName) = "") AND V(MyVariableName) <> "")
This should be turned into some kind of query which gets the value of MyComponentName and MyOtherComponentName and (in this case) compares them for equality.
They don't necessarily want to just compare for equality, but to be able to determine whether a component / variable value is greaterthan or lessthan etc.
Basically it's a free-form statement that gets converted into something similar to an IF statement.
I've tried this:
Sub TestCondition()
Dim Condition as string = String.Format("{0} = {1}", _
Component("MyComponent").Value, Component("MyOtherComponent").Value)
If (Condition) Then
' Do Something
Else
' Do Something Else
End If
End Sub
Obviously, this does not work and I honestly didn't think it would be so simple.
Ignoring the fact that I'd have to parse the line, extract the required operators, the values from components or variables (denoted by a C or V) - how can I do this?
I've looked at Expression Trees but these were confusing, especially as I'd never heard of them, let alone used them. (Is it possible to create an expression tree for dynamic if statements? - This link provided some detail on expression trees in C#)
I know an easier way to solve this might be to simply populate the form with a multitude of drop-down lists, so users pick what they want from lists or fill in a text box for a specific search criteria.
This wouldn't be a simple matter as the ERP doesn't allow you to dynamically create controls on its forms. You have to drag each component manually and would be next to useless as we'd potentially want at least 1 rule for every form we have (100+).
I'm either looking for someone to say you cannot do this the way you want to do it (with a suitable reason or suggestion as to how I could do it) that I can take to my manager or some hints, perhaps a link or 2 pointing me in the right direction.
If (Condition) Then
This is not possible. There is no way to treat data stored in a string as code. While the above statement is valid, it won't and can't function the way you want it to. Instead, Condition will be evaluated as what it is: a string. (Anything that doesn't boil down to 0 is treated as True; see this question.)
What you are attempting borders on allowing the user to type code dynamically to get a result. I won't say this is impossible per se in VB.Net, but it is incredibly ambitious.
Instead, I would suggest clearly defining what your application can and can't do. Enumerate the operators your code will allow and build code to support each directly. For example:
Public Function TestCondition(value1 As Object, value2 As Object, op as string) As Boolean
Select Case op
Case "="
Return value1 = value2
Case "<"
Return value1 < value2
Case ">"
Return value1 > value2
Case Else
'Error handling
End Select
End Function
Obviously you would need to tailor the above to the types of variables you will be handling and your other specific needs, but this approach should give you a workable solution.
For my particular requirements, using the NCalc library has enabled me to do most of what I was looking to do. Easy to work with and the documentation is quite extensive - lots of examples too.

VB.net Strange Conditional Statement (IF)

Was wondering if someone could lend me their expertise. Pretty new to Vb.net and have come across this conditional statement in one of our products. Could someone please confirm the validity of the statement and explain what's going on here? I've tried numerous searches, but I cannot find anything related.
If (IsDBNull(dr("someID")), "0", dr("someID")) = someID.ToString() Then
I have changed the "id" value names as it's code from a commercial product, but the ID's used were all the same variable (ints).
Thanks for any input you can offer on this!
Joe
PS: The reason I can't check this at run time is because of how the product operates.
It is an inline If statement
If(condition,iftrue,iffalse) if condition is true evaluate and return iftrue else iffalse
The If operator in VB.NET 2008 acts as a ternary operator.[ REFERENCE]
Example:
Dim foo as String = If(bar = buz, cat, dog) 'Condition satisfied then it'll return cat else dog.
The statement is checking to see if the dr("SomeID") equals the value someID.ToString. The reason the If is required is because you need to check if the dr("someID") Is Null. If it is 0 is used instead which presumably should not be equal to someID.
It is the same as doing the following:
If Not IsDBNull(dr("someID")) Then
If dr("someID").ToString = someID.ToString Then
End If
End If
I would suggest that something like this would be more appropriate (checking integer values instead of comparing strings)
If(IsDBNull(dr("someID")), 0, CInt(dr("someID"))) = someID Then
I would also suggest Turning Option Strict On as the code you posted should not compile!

In VB.NET why should I use Select, instead of If?

I've recently graduated and started a real job. In our training they've been exposing us to VB.NET and a lot of the features they use here. In some of the examples, they've used Select statements (and in a few places they were used where an If/Else really should have been used).
The only time that I've used a switch/select statement in other languages (other than assignments that required it) has been when I wanted the fall through to the next statement.
Given than VB.NET has no fall through, what (if any) cases are there to use the Select statement? Are there any cases when it provides advantages over and If/ElseIf statement?
Select Case, not just Select.
To me, it's one of the best features of the language.
It's much more visual when you have several possible values to test against.
select case some_var
case 1
something()
case 2
something_else()
case 3
etc()
end select
It's much more readable when it comes to testing ranges:
select case some_var
case 1 to 10
something()
case 20 to 30
something_else()
case is > 100
etc()
end select
It's much more readable when you have a bunch of more complex conditions to test, making sure only one is selected:
select case true
case string.isnullorempty(a_string)
something()
case a_string.length < 5
something_else()
case a_string = b_string
etc()
end select
It's superior to C/C++ switch in the sense that it allows expressions as branching points, not just constants.
When using constants as branching points (example 1), compiler is able to generate a more optimised code with direct jumps.
Select tells the compiler that every compare (If) in the analogous set of If/Else blocks is on the same value, and this allows it to make certain optimizations that are harder to be sure of otherwise. For example, it might be more eager to generate machine code that holds that value in a cpu register (that's just hypothetical... different compilers can do what they want).
Also, some of us find Select a lot more readable. It is important to follow the coding standards of whatever team or unit you find yourself.
First off, VB does have fall through, it's just not as obvious. The "fallthrough" in VB is just setting one case to have multiple values:
Dim number As Integer = 8
Select Case number
Case 6,7,8
' do stuff
Case Else
' do default stuff
End Select
As for its advantages, it's way easier to write one Select statement than say, more than three If/ElseIf statements that all test against the same value.
If you are going to do several different things based on the input comparison/range comparison if it's if-elseif+ then use Select instead of crazy if-elseif blocks.
VB.NET's Select statement has some cool features as well, so ensure that you know all the features.
There is a situation where Select Case can be much more efficient than If: when you have a list of "Or" clauses in the If condition and you do not need to evaluate them all to establish the truth of the condition. Suppose you had an if statement such as this:
If A() Or B() Then
DoSomething()
ElseIF C() or D() Then
DoSomethingElse()
Else
DoTheDefault()
EndIF
In this case, to evaluate the first if statement, both functions A() and B() are executed, and similarly for the second if statement when A() and B() are both false. If A() returns true, then the value of B() is immaterial and, unless it changes the program state in a way that you actually want it to (generally not good practice), the execution of B() is redundant. The compiler is constrained by the requirement that all parts of the test MUST be executed before concluding on a value (optimisation of the test is not allowed according to the language spec).
You could separate the conditions into multiple IfElse statements to optimise it yourself but this makes the code less readable and increases the danger of errors when changes are made later. I find that using Select Case is better in this situation:
Select Case True
Case A(), B()
DoSomething()
Case C(), D()
DoSomethingElse()
Case Else
DoTheDefault()
End Select
Now, if A() returns True then B() is not evaluated at all. The evaluation of the conditions is in the sequence listed, so you can help to optimise your code by putting the tests in the order of most likely to return True or least expensive to execute (depending on the application).