views:

87

answers:

7

What's best practice (in VB.Net):

Function GetSomething() as String
    GetSomething = "Here's your string"
End Function

or

Function GetSomething() as String
    Dim returnString as String = "Here's your string"
    Return returnString
End Function

Obviously, neither of these implementations make any sense, but they're just meant to illustrate my point. Is there anything to be gained by using GetSomething itself to store the return value instead of declaring returnString locally and then returning that (does it avoid having an extra string allocated/instantiated - and if so, are there any performance/memory benefits)?

+1  A: 

Try it both ways then use .Net Reflector to see if the generated IL is different.

David
Or better yet - someone already knows this :)
d7samurai
A: 

I'm guessing you mean in VB? The language you're talking about is relevant. The benefit of #1 is it effectively does the same as #2 for you. With a return statement processing ends immediately, but with a returnable item, you can set it clear up lose ends, and then end processing.

Function GetSomething() as String
    GetSomething = "Here's your string"
    db.close();
End Function

Code #2 is more similar to the syntax of other languages (C# for example) so either to help others understand, or to keep style consistent across all code bases, it might be preferable. In terms of function code #2 is a bit redundant, but it really depends on what's going on behind the scenes, the compiler likely renders both of the above identically in a compiled state.

Rudu
I tend to use technique #1 myself, partly because I somehow find it "cleaner" to declare fewer variables, but also because of the ability to fill the final return value and then clean up before the function exits, especially in branched code segments.
d7samurai
A: 

You could use reflector to check out out, but, in all honesty, whatever performance penalty there might be for something like this would fall squarely under the heading of "Premature optimization" .

From a syntactic perspective, the {Return "a value"} syntax tends to encourage multiple exit points from the method, which is often seen as a bad practice. But if the method is small, then I don't see that code readability would suffer from it.

OTOH, the {var = value; Return Var} syntax tends to promote a single exit point at the end of the function.

drventure
Since it would be a systematic penalty that’s incurred, this isn’t a premature optimization at all. Not having thought about the performance implications of such an ubiquitous feature would to the contrary be a careless design.
Konrad Rudolph
Meh. Splitting hairs, I think. Sure, be aware that there +might+ be a slight performance hit, but in the grand scheme of things, whatever that hit might be could not possibly be anything close to actually significant, so it's really not worth even investigating, unless you're just curious. And hey, nothing wrong with being curious.
drventure
+1  A: 

I prefer having explicit exit points so I always use Return. Furthermore, I don’t like VB’s decision to use the function name as the name of the return variable (why not Result, like in Pascal?) because this makes it inconsistent when the function returns an array:

Function Foo() As Integer()
    Foo = New Integer(2) { }
    Dim a = Foo(1) ''// Recursive call or access to return value element?
End Function

Of course that’s a recursive call (otherwise those wouldn’t be possible any longer). But I’m very annoyed by such inconsistencies so I don’t use the syntax.

On the other hand, there’s the advantage of a standardized name for the return value holder, and that’s definitely an advantage over the Return method.

Either way, VB generates the same code.

Konrad Rudolph
Funnily enough - the example you provide here is exactly the experience I just had when implementing a function that (takes and) returns a byte array. It gave me a StackOverflowException - because it kept calling itself. It took me a minute to figure out why my code suddenly would hang, and it made me wonder whether I should choose the "Return way" as "my way" instead (since I like to be consistent in my code), and this prompted me to ask this question here to get some discussion/input on the matter.
d7samurai
Maybe it's worth mentioning that you can, of course, still have explicit exit points when using the Function to hold the variable, through `Exit Function`.
d7samurai
+4  A: 

Interesting question. I ran this:

Function GetSomething1() As String
    GetSomething1 = "Here's your string"
End Function

Function GetSomething2() As String
    Dim returnString As String = "Here's your string"
    Return returnString
End Function

through IL DASM and here are the results:

Debug build:

.method public instance string  GetSomething1() cil managed
{
  // Code size       9 (0x9)
  .maxstack  1
  .locals init ([0] string GetSomething1)
  IL_0000:  nop
  IL_0001:  ldstr      "Here's your string"
  IL_0006:  stloc.0
  IL_0007:  ldloc.0
  IL_0008:  ret
} // end of method Form1::GetSomething1

.method public instance string  GetSomething2() cil managed
{
  // Code size       13 (0xd)
  .maxstack  1
  .locals init ([0] string GetSomething2,
           [1] string returnString)
  IL_0000:  nop
  IL_0001:  ldstr      "Here's your string"
  IL_0006:  stloc.1
  IL_0007:  ldloc.1
  IL_0008:  stloc.0
  IL_0009:  br.s       IL_000b
  IL_000b:  ldloc.0
  IL_000c:  ret
} // end of method Form1::GetSomething2

Release build:

.method public instance string  GetSomething1() cil managed
{
  // Code size       8 (0x8)
  .maxstack  1
  .locals init ([0] string GetSomething1)
  IL_0000:  ldstr      "Here's your string"
  IL_0005:  stloc.0
  IL_0006:  ldloc.0
  IL_0007:  ret
} // end of method Form1::GetSomething1

.method public instance string  GetSomething2() cil managed
{
  // Code size       8 (0x8)
  .maxstack  1
  .locals init ([0] string GetSomething2,
           [1] string returnString)
  IL_0000:  ldstr      "Here's your string"
  IL_0005:  stloc.1
  IL_0006:  ldloc.1
  IL_0007:  ret
} // end of method Form1::GetSomething2

You'll note that there are more operations in the debug build but not in the release build.

So to answer your question, it seems that declaring the variable costs a little bit extra in debug builds, which is often the case (optimization not turned on or is not as much optimized). But in the release build (as expected) the optimizer is removes this unecessary operation.

steinar
So in terms of compiled code size/instantiation/memory allocation at runtime, it seems to make no difference. Could more complex function implementations skew this result? As in situations where the variable is used for actual processing within the function and/or there is code branching/multiple exit points etc? If not, I guess that leaves the issue of coding practicalities more than performance per se..
d7samurai
I think there's no doubt that the compiler can't get it right in every situation, but in general I would not think about these issues at all - always go with code clearness. Note that the C/C++ community is slowly moving away from writing assembly code themselves (which had major benefits in performance before) as the benefits are slowly fading away - it's getting more and more difficult to find situations where an assembly programmer knows better than the compiler. The same applies here.
steinar
+1  A: 

Although I can't add comments yet, this question seems to have already been asked here:

http://stackoverflow.com/questions/451025/vb-net-function-return

ColorEyes
A: 

The execution difference is essential nil, so it would depend on which is easier to understand and maintain. I personally assign a variable to the function name before an exit or use the return statement, rather than using the function name as a variable throughout the function. It seems a little odd or ambiguous to me if I use the function name as a variable throughout the function.

If I remember right, return() was added as the return statement to a function between VB6 and VB.Net, probably to make it more like other languages. This would explain why there are the two ways to do the same thing.

xpda