(Micro Optimisation) - Exit function or let it run through all code - vb.net

I am curious if Exit Sub, Exit Function, among others should be avoided when coding? I have read in various places that it is a bad practice and that you should, if possible, avoid it.
I have provided a function below to demonstrate what I mean:
Function Test()
Dim X As Integer
X = 5
If X = 10 Then
Test = True
Exit Function
Else
Test = False
Exit Function
End If
End Function
In the case above, the Exit Function isn't necessary since the entire code will be able to finish the entire routine without an issue. But by adding it, will it cause some issues?

The style you're using is from the VB5 and VBA era, which didn't support Return statement and we needed to assign the return value directly to the function name. In VB.NET you should always use Return assignment. Return will do both the assignment and the exit call in one statement.
Regarding your particular example, my impression is that the Exit Function statement does nothing more than doing a GoTo to the nearest End Function line. So these statements in your case are redundant and might get striped off by the compiler (not sure about this one).
Note that Exit statements become a nightmare from code-readability point of view. I have recently been a victim of this particular problem. Visual Basic is such a verbose language and Exit statements go unnoticed by the reader. A structured If/Else block is FAR more readable.

This depends on the current context of your code. If you are within a block (be that a loop, Sub or function etc.) and are attempting to leave, the Exit Statement will do fine.
The Return Statement will also work the same as a Exit Function or Exit Sub, see the answer to this SO question. But personally I prefer the exit statement in a function when I wish to return control to the calling code, but have no value to return.

In practically every case, there's a "better" approach than using Exit Function.
The following example will give the same result, but is shorter, and in my opinion much clearer.
Function Test() As Boolean
Dim X As Integer
X = 5
Return (X = 10)
End Function

To clarify a little, as #dotNET said. This is pre .net code. In dot net, you would change your code slightly to
Function Test() As Boolean
Dim X As Integer
X = 5
If X = 10 Then
Return True
Else
Return False
End If
End Function
This defines test as a function that returns a Boolean result and you use the Return statement to err.. return the result back to the calling statement and exits the function immediately at the aforementioned Return statement
for example ..
Dim result As Boolean
result = test

Related

Is there an equivalent of Python's pass statement in VBA?

I would like to know if there is an equivalent of Python's pass statement in VBA.
I am using Excel 2016.
The use of Stop (see this answer) seems to be the best thing to do if you are looking for some "non-statement" that you can use to insert a breakpoint, because the Stop command causes the code to break when it is reached, i.e. you don't even need to mark it as a breakpoint because it is one.
You might also like to consider using Debug.Assert some_logical_expression, which will break automatically whenever the logical expression evaluates to False. So Debug.Assert False would be equivalent to Stop, and Debug.Assert x = 3 would be equivalent to If x <> 3 Then Stop.
In Python you need the Pass, because otherwise the methods will not run.
In VBA, its perfectly ok if you leave an empty method like this:
Public Function Foo() As String()
End Function
Maby you are looking for the "Stop" statement.
The good thing about it is that it doesn't clear your variables.
It depends what are you trying to achieve.
You may declare a Label and then use GoTo Label e.g. declare a label (like Skip:)in your code where you want to jump if a condition is met and then use GoTo Skip
Below is the small demo code to give you an idea about this...
Dim i As Long
For i = 1 To 10
If i = 5 Then GoTo Skip
MsgBox i
Next i
Skip:

Syntax error using IIf

This is a simple question I hope. I learned about IIf today and want to implement it in some cases to save a few lines.
IIF(isnumeric(inputs), resume next, call notnum)
This is in red meaning there is a syntax error, how fix this? I have scanned MSDN article on this so I am not being lazy here.
That's not how the IIf function works.
It's a function, not a statement: you use its return value like you would with any other function - using it for control flow is a bad idea.
At a glance, IIf works a little bit like the ternary operator does in other languages:
string result = (foo == 0 ? "Zero" : "NonZero");
Condition, value if true, value if false, and both possible values are of the same type.
It's for turning this:
If foo = 0
Debug.Print "Zero"
Else
Debug.Print "NonZero"
End If
Into this:
Debug.Print IIf(foo = 0, "Zero", "NonZero")
Be careful though, IIf evaluates both the true and the false parts, so you will not want to have side-effects there. For example, calling the below Foo procedure:
Public Sub Foo()
Debug.Print IIf(IsNumeric(42), A, B)
End Sub
Private Function A() As String
Debug.Print "in A"
A = "A"
End Function
Private Function B() As String
Debug.Print "in B"
B = "B"
End Function
Results in this output:
in A
in B
A
That's why using IIf for control flow isn't ideal. But when the true result and false result arguments are constant expressions, if used judiciously, it can help improve your code's readability by turning If...Else...End If blocks into a simple function call.
Like all good things, best not abuse it.
You cannot use iif like this.
Here is a possible way to solve this:
if isnumeric(input) then
do something ...
else
call notnum
end if
IIf returns a value. As Mat's Mug stated, you can use it, to hand data into another method or function, but you can't call a procedure or function, which has no return value.
IsNumeric() for the conditional is okay, though.

VBA UDF fails to call Range.Precedents property

I am trying to write a simple UDF, which is supposed to loop through each of the cells of a given_row, and pick up those cells which do not have any precedent ranges, and add up the values.
Here is the code:
Public Function TotalActualDeductions(given_row As Integer) As Integer
Total_Actual_Deduction = 0
For present_column = 4 To 153
Set precedent_range = Nothing
If Cells(2, present_column) = "TDS (Replace computed figure when actually deducted)" Then
On Error Resume Next
Set precedent_range = Cells(given_row, present_column).Precedents
If precedent_range Is Nothing Then
Total_Actual_Deduction = Total_Actual_Deduction + Cells(given_row, present_column)
End If
End If
Next
TotalActualDeductions = Total_Actual_Deduction
End Function
If I try to run it by modifying the top declaration, from:
Public Function TotalActualDeductions(given_row As Integer) As Integer
to:
Public Function TotalActualDeductions()
given_row = 4
then it runs successfully, and as expected. It picks up exactly those cells which match the criteria, and all is good.
However, when I try to run this as a proper UDF from the worksheet, it does not work. Apparently, excel treats those cells which have no precedents, as though they have precedents, when I call the function from the worksheet.
I don't know why this happens, or if the range.precedents property is supposed to behave like this.
How can this be fixed?
After a lot of searching, I encountered this:
When called from an Excel VBA UDF, Range.Precedents returns the range and not its precedents. Is there a workaround?
Apparently, "any call to .Precedents in a call stack that includes a UDF gets handled differntly".
So, what I did was use Range.Formula Like "=[a-zA-Z]" , because it satisfied my simple purpose. It is in no way an ideal alternative to the range.precedents property.
Foe a more detailed explanation, please visit that link.

What are a good No OP operation for vb.net?

Something we can just put break point on while making sure it doesn't do anything else.
In c, that would be while(false);
What to do in vb.net?
If you always need it to break there you can put
Stop or Debugger.Break()
If you really want a No-Op for some reason (could this turn into a contest for the most ineffectual single line of code?!), how about these?
System.Threading.Thread.Sleep(1) - 1ms is unlikely to have a huge impact outside of a loop
Debug.Write("") - doesn't appear to output anything.
There is a legitimate use-case for this.
When a temporary breakpoint is required after the statement of interest and this is the last line inside an if statement, an extra no-op type statement is required to place the temporary breakpoint on.
In this case I use:
If someCondition >0 Then
doSomething
Space (1) 'Dummy line to place breakpoint
End If
This returns a string containing one space, but does not assign it to anything. I use it in VBA, but it's also supported in .net
My two cents...
You can combine any series of commands onto one line with colons:
If False Then : End If
Select Case False : Case Else : End Select
I've also made it into a sub. Then it gets a recognizable name of own:
'Definition...
Public Sub noop () 'Or Private, Protected, etc.
End Sub
'Usage...
Sub Main()
If sometest Then
noop
Else
MsgBox "test is false"
End If
End Sub
Very strange question, you could place a BreakPoint about anywhere in the code. But here are some useless lines :
Do While False
Loop
While False
End While
Even the following :
Dim hello = Nothing
Or this :
Format("", "")
A no-op statement is also useful as an aid to document code nicely and make it more easily understandable. You could for example put in a statement like A = A.
For example:
If MyNumber => 100 then A = A
Else:
I know this is an old query, but for what it is worth, my preferred solution to the original question is
Debug.Assert (vbTrue)
If you wanted, you could use a variable instead of vbTrue and then enable/disable all breakpoints in your code by changing one variable
Dim bDisableBreakpoints as Boolean: bDisableBreakpoints = vbTrue
'your code here
Debug.Assert (bDisableBreakpoints)
'rest of your code
Simply change bDisableBreakpoints to vbFalse and the breakpoints will be set wherever you have used Debug.Assert
My personal favorite is
dim b=1
Then I put a breakpoint there.

Syntax: "Exit Sub" or "Return" in VB.NET subroutines

Both "Exit Sub" or "Return" seem to accomplish the same thing -- exit a subroutine. Is there any difference in how they work under the covers?
That is,
Private Sub exitNow()
Exit Sub
End Sub
or
Private Sub exitNow()
Return
End Sub
From the doc:
In a Sub or Set procedure, the Return statement is equivalent to an Exit Sub or Exit Property statement, and expression must not be supplied.
So they're the same in this context.
(Return (<value>) is used in functions and property.get's. Obviously slightly different in that context).
I tend to prefer Return over Exit Sub. Because once in a while you change from Sub to Function. In this case Exit Sub could be converted to Exit Function, but this assumes that there was a previous assignment to the function name (alike VB 6), which most probably didn't happen. Return would catch this situation - if the method should return a value, Return with no argument will fail at compile time.
If you inspect the IL output of the 2 statements, they are the same. However, since ’return’ is meant for pushing something back to the caller, so strictly speaking, ‘Exit Sub’ is more suitable for using in a Sub.
They are the same in this context.
However, from the code readability point of view, "Exit Sub" would be clearer since the "Return" indicates that something some value is being used as an output (which is not the case with Sub-routines).
First of all, Procedures comes with sub, we should know that we are working on specific procedures that don't return a specific value with the ability of passing some specific parameters or even without passing any parameter. Such as:
Print something().
Calculate the factorial of integer number CalcFact(X).
Do some processes for a specific task.
Function is a specific process programmed to achieve a specific task by also passing some specific parameters, and it has to return some value that can be used to to complete the overall task, such as validation the user name and user pass.
In short Sub Doesn't return value and we call it directly "Print HelloWorld()" , whereas functions do such as:
ValidUsersNameAndPass("Johne","jOhNe13042019") ' This could return a Boolean value.
ValidUsersNameAndPass("Johne","jOhNe13042019"); // This could return a Boolean value.
I wanted to confirm that they act the same in lambda expressions too, and they do:
Sub test()
Dim a As Action = Sub() Exit Sub
Dim b As Action = Sub() Return
a()
b()
MsgBox("Yes they do!")
End Sub
While there are exceptions like guard clauses, in most cases I would consider either a sign that the method is too long.