Multiple returns versus Exit for - performance

I have the following VB.NET code (but for each loops are in most languages, thus the language-agnostic tag):
Public Function VerifyServiceName(ByRef sMachineName As String, ByRef sServiceName As String) As Boolean
Dim asServices As System.ServiceProcess.ServiceController() = System.ServiceProcess.ServiceController.GetServices(sMachineName)
Dim bVerified As Boolean = False
For Each sService In asServices
If sService.DisplayName = sServiceName Then bVerified = True
Next
Return bVerified
End Function
If I have X number of services to loop through, and my service name is #3. Is it better to have multiple return statements or an exit for? Or is there a more efficient way of writing this function?
I know that the time difference between looping X times and looping through 3 times could be marginal for what I am doing, but I always have performance on the brain.

I personally believe having one return at the bottom is far more readable and easier to debug than if you have return statements everywhere, as you can never tell when the function is going to exit so you end up putting breakpoints on every return statement instead of just once at the end, for example.
I think it's all down to preference though, as there are valid arguments for both ways.

Found more discussion here about the subject. I guess I am not that proficient at searching.

I would never use a goto as the target of another goto, so if there's some additional processing at the end of the function, use "break / Exit For", otherwise just return early. Otherwise you end up with lines that mean "return" but say "break"... that doesn't help maintainability.

Related

Is Call MagicFunction(intData1, intData2, Dim intData3) a valid statement in vbs?

I'm not really sure how to phase it any other way.
The thing is, i'm trying to merge functions with the same name in vbs. Sometimes, the function appears in different forms in other parts of the system. If they are too different, I regretfully leave them as they are. However, if the differences are minor (like having one of the functions only having one variable more than the others, which i can then check for in-function), I'd like to add a variable that would be a stand in.
I already know that Optional variables are not possible in vbs, and I've already had experience with passing an array of variants (works like a charm), but I believe this case is a bit different.
Dim is not correct here. You can do for example:
Public Function MagicFunction(intData1, ByRef intData2, ByVal intData3)
' some code
End Function
and to call it:
MagicFunction 3, iCount, ""
to have "optional arguments", you can only use an array an parse it (for example using UBound(aTab) to select the correct case
Public Function MagicFunction(ByVal aTab)
Select Case UBound(aTab)
Case 1: MagicFunction1 aTab(1)
Case 2: MagicFunction2 aTab(1), aTab(2)
Case Else: MsgBox "function called with more than 2 args" '<-- Should never go there
End Select
End Function
With different version of your function depending on the number of argument, MagicFunction1, MagicFunction2... It's ugly but do the trick!
Another possibility is to use empty strings as argument, and define how your function ignore a part when the string is empty (or to be more accurate, call with a specific key, like "IGNORE_KEY")
I hope I'm answering your question!

Why is a single exit point for a function preferred?

I have been using multiple return statements in a function for a while and I find it more readable and avoid many conditional blocks. I found many Q & A's suggesting single exit point for a function and I din't find a reasonable explanation for the same.
Many code analysis tools suggest to have a single exit point for the function.
Can anyone tell me why this approach is preferable?
Thanks
By having a single return statement, you often use less code. For example:
-(bool)testMethod {
If(condition)
return true;
}
If the condition is not met, it will return false, so theres no need to add } else { return false.
In my experience it's always best to write the code as efficiently as possible, and there are usually more efficient ways than writing a bunch of if else statements

Objects in loops and return values

I have a function that is similar to this:
public sub TestFunction() As Boolean
On Error GoTo NewError:
Dim testObject As New TestObject
For TestVaiable 0 to 1000
TestObject.TestMethod(TestVariable)
Next
TestFunction = True
Exit function
NewError:
TestFunction = False
End Function
I have two questions:
1) Is it bad practice to keep reusing an object in a loop? I don't think it is
2)Is it bad practice to return a boolean (false) if there is an error?
It's good practice to reuse a variable in a loop.
It's good practice to reuse an object that will either be in the same state for the whole loop, or have a very simple change that relates clearly to the nature of the loop.
It's bad practice to reuse an object in such a way that it makes it harder to see what's going on with it.
It's good practice to return quickly from a Sub or Function .There's a superstition in VB about returning early that comes from other languages that are irrelevant to it, sort of a computer equivalent to people thinking you shouldn't split infinitives in English because you can't in Latin. It's nonsense.
It's bad practice to just return from a Sub or Function when you encounter an error, without any further handling unless that is the most sensible thing to do for some reason you can explain in a short comment of less than about 200 characters.
It's bad practice not to put in that comment of less than 200 characters explaining why it's okay to just return when that error happened.

Return values from VB6 function

I have a VB6 function, which executes an SQL delete. The function returns a boolean depending on whether or not the deletion was successful:
Public Function Delete(ByVal RecordID As Integer) As Boolean
On Error GoTo ErrorGenerated //Execute SQL delete
Delete = True
Exit Function
ErrorGenerated: Delete = False
End Function
I read somewhere that it is better to return an integer, which dictates whether or not the deletion was successful. However, there can only be two outcomes from running the function from what I can see i.e. deleted or not deleted (not deleted if an error is thrown). Is it better to return an integer?
I'd suggest your best bet is to return an enumerated type; each value for the enumeration can then explain to the caller what the problem is in a clear and unambiguous way, and new error reasons can be added later as required without breaking anything. Something like...
Public Enum DB_ERRS
Success
NoConnection
FailedForThisReason
FailedForThatReason
FailedForOtherReason
Failed
End Enum
Then all your database access functions could return a value of this type...
Public Function Delete(ByVal RecordID As Integer) As DB_ERRS
On Error GoTo ErrorGenerated
Execute SQL delete
Delete = Success
Exit Function
ErrorGenerated:
If Err.Number = this Then
Delete = FailedForThisReason
Else
Delete = Failed
End If
End Function
Intellisense will even help you fill them in.
This is rather subjective.
One would say, return a boolean because it's as simple as it gets.
Another one would say, return an integer, because later you might want to add a third status, such as "archived," and it would break existing code.
And someone else would say, Ditch that C-style return codes. Create a sub that doesn't return anything, and raise an exception in case you need to indicate failure.
I personally prefer exceptions. But it's up to you to decide.
In terms of size, an integer is a 32-bit signed integer, while the boolean data type doesn't really have a defined size. However, it also depends on the context from where you've read about using integers over booleans.
For SOME, the difference is irrelevant when using it as a return value from functions.
However, it can be something of a preference in stored procedures if you're also considering the return value from the stored procedure. The evaluation of booleans (when converted to numbers) may lead to it being treated like a bit (0 and 1).. In any case, it's more of a subjective approach. Integers allow more flexibility, while booleans offer limitation and simplicity. Which is better? I think it's almost entirely up to you, your preference, your coding standards, your company's coding standards, or whatnot..
Just to share a link on data types :
http://msdn.microsoft.com/en-us/library/aa383751(v=vs.85).aspx
I'll throw my opinion in. I personally think that returning a boolean value is the right thing to do. Do you really care why it failed to delete? Not normally, there are only a few reasons why a delete could fail in the first place (file locked or lack of permissions). If you need to return the reason for failure so it can be handled differently in some way, then yes, return an integer. Now personally, I don't like magic numbers, so I would never return an integer and would return an enum value instead.

Which method will perform better? (Or is there not enough of a difference to matter?)

Which (if any) of the following will give the smallest performance hit? Or is the difference so small that I should use the most readable?
In the same page I've noted 3 styles used by previous maintainers:
Method 1:
If (strRqMethod = "Forum" or strRqMethod = "URL" or strRqMethod = "EditURL" or strRqMethod = "EditForum") Then
...
End If
Method 2:
Select Case strRqMethod
Case "Reply", "ReplyQuote", "TopicQuote"
'This is the only case in this statement...'
...
End Select
Method 3:
If InArray("Edit,EditTopic,Reply,ReplyQuote,Topic,TopicQuote",strRqMethod) Then
...
End If
.
.
.
'Elsewhere in the code'
function InArray(strArray,strValue)
if strArray <> "" and strArray <> "0" then
if (instr("," & strArray & "," ,"," & strValue & ",") > 0) then
InArray = True
else
InArray = False
end if
else
InArray = False
end if
end function
Moving away from Classic ASP/VBScript is not an option, so those comments need not bother to post.
You can benchmark this yourself to get the best results, as some performance will differ depending on the size of the input string.
However, I will say from a maintenance perspective, the second one is a bit easier to read/understand.
Well Method 3 is clearly going to perform worse than the other two.
Between Method 1 and Method 2 the difference is going to be marginal. Its worth remembering that VBScript doesn't do boolean expression short cutting hence in Method 1 strRqMethod will be compared with all strings even if it matches the first one. The Case statement in Method 2 at least has the option not to do that and likely will stop comparing when the first match is found in the set.
Utimately I would choose Method 2 not because I think it might be faster but because it expresses the intent of the code in the clearest way.
Educated guess:
Performance-wise, first two approaches are roughly equivalent; third method is very likely slower, even if it gets inlined.
Furthermore the differential between the first two are likely in the micro-seconds range, so you can safely consider this to be a bone fide case of premature optimization...
Since we're on the topic of OR-ed boolean evaluation, a few things to know:
Most compilers/interpreters will evaluate boolean expressions with "short circuit optimization", which means that at the first true condition found, the subsequent OR-ed conditions are NOT evaluated (since they wouldn't change the outcome). It is therefore a good idea to list the condition in [rough] decreasing order of probability, i.e. listing all the common cases first. (Also note that short circuit evaluation is also used with AND-ed expressions, but of course in the reverse, i.e. at the first false condition, the evalation stops, hence suggesting to write the expression with the most likely conditions to fail first).
Comparing strings is such a common task that most languages have this done in a very optimized fashion, at a very low level of the language. Most any trick we can think to improve this particular task is typically less efficient than the native operator.
As long as this is not done 100.000 (in other words: a lof of) times in a loop, it makes no difference. Although it is parsed code, we may still assume that the parsing is done swift and quickly enough not to make a difference.
I found severe performance problems only when you are concatenating a lot of strings - like I once found out when running a page, adding debug code to a global string to be able to dispay the debug only at the bottom of the page. The longer the page was, the more code it ran, the more debug code I added, and the longer the time it took to display the page. Since this page was doing some database access, I presumed it was somewhere in that code that the delay occured, only to found out that it was just the debug statements (to be honest, I had a log of debug string concatenated).

Resources