Introduction
Functions VS Subroutines and By Val Vs by Ref in VB.NET
The purpose of this article is to clear the minds of the developers on Methods in VB.net who are reading this article.
While doing Code review for client, I found out there are various Subroutines which has reference types (Like textboxes, Array Lists) as BY Val Parameters.
There were functions which doesn�t had a return type
Functions which doesn�t return anything.
I hope that after reading this article, Readers will have a better understanding of Methods, Functions, and Subroutines in VB.NET.
METHODS:
Methods contain the executable statements of a program.
There are two types of methods: subroutines and functions.
For purpose of this article I will be sticking to Subroutines and functions and By Val and by ref Parameters.
More about other method types such as Shared, Non shared, External, Overridable Methods can be found http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vbls7/html/vblrfvbspec7_1_6_2.asp
Functions and subroutines are the most basic building block you can use to organize your code.
Ideally, each function or subroutine will perform a distinct, logical task.
By breaking your code down into procedures, you not only simplify your life, but you also make it easier to organize your code into classes and step into the world of object-oriented programming.
Functions are very similar to subroutines�their syntax is nearly identical, and they can both perform the same actions. Functions, however, return a value to the code that called it.
But Most of us stop thinking after this. At least I did.
Returning a value is not the only difference between a Function and Subroutine.
Interesting �Hmmm�..read further.
I am going to use ILDASM to show that the Vb.net Subroutines are more efficient and performance beneficial than VB.net functions.
I made an ASP.net project with Vb.net.
Here are two methods I made (one Subroutine and one Function)
Public Sub TESTSUB ()
End Sub
Public Function TESTFUC()
End Function
And for those of you who are C# fans, here is a sample C# function.
public void TestCSharp()
{
}
Now look at their MSIL (Please read http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cptools/html/cpconmsildisassemblerildasmexe.asp , if you are new to ILDASM and MSIL)
.method public instance void TESTSUB() cil managed
{
// Code size 3 (0x3)
.maxstack 8
IL_0000: nop
IL_0001: nop
IL_0002: ret
} // end of method WebForm1::TESTSUB
.method public instance object TESTFUC() cil managed
{
// Code size 3 (0x3)
.maxstack 1
.locals init ([0] object TESTFUC)
IL_0000: nop
IL_0001: ldloc.0
IL_0002: ret
} // end of method WebForm1::TESTFUC
.method public hidebysig instance void TestCSharp () cil managed
{
// Code size 2 (0x2)
.maxstack 0
IL_0000: nop
IL_0001: ret
} // end of method Class1:: TestCSharp
Look at these MSIL instructions, C# has the cleanest implementation of a void method; the size of the evaluation stack is 0 and there is nothing except a mandatory nop, followed by return.
VB.NET sub is next, but mysteriously it has a .maxstack 8 statement at the top, what are they thinking?? Although that does not mean the run time evaluation stack is 8, the statement is used only for static analyzer by the verifier during the assembly loading phase. I would be glad if any of you can help me understanding why the Sub has a .maxstack 8.
VB.NET function with no explicit return type is the ugliest. To preserve generosity, the all mighty object is used as the base type so that even if you return an arraylist of arraylists of arraylists of... is fine.
So I reached to following conclusion (Please correct me if you feel something is incorrect)
1. VB.Net Subroutine is faster than Function
2. You should never use a Function without a return type, it won�t give you a compilation error but it hinders the performance.
Now lets explore Byval and Byref
Now let�s Move on to have a closer look at By Val and By Ref parameters. If you are interested in other parameter types well read this
When you pass a variable By Val a new instance of the variable is created and given to the routine being called.
Any changes made to the value of this variable have no effect on the value of the original variable that was passed in.
If you instead pass in a variable ByRef, any changes you make to this variable also change its value outside the routine
Lets go more deep��
In VB 6, if the parameters to a function or subroutine were not explicitly prefaced with the ByVal or ByRef keywords, arguments were passed to that routine by reference, and modifications made to the argument in the function or subroutine were reflected in the variable's value once control returned to the calling routine.
In VB .NET, on the other hand, if the ByRef or By Val keyword is not used in a parameter, the argument is passed to the routine by value, and modifications made to the argument in the function or subroutine are discarded once control returns to the calling program.
There is some confusion regarding which one is faster.
Some books say By Val is much better because ByRef is higher overhead because the data must be copied to the sub or function and then copied back once the sub or function completes.
This is Incorrect. To prove this. Lets again take help of ILDASM.
Public Sub TEST_SUB_BY_VAL(ByVal i As Integer)
End Sub
Public Sub TEST_SUB_BY_REF(ByRef i As Integer)
End Sub
MSIL is like this
.method public instance void TEST_SUB_BY_VAL(int32 i) cil managed
{
// Code size 3 (0x3)
.maxstack 8
IL_0000: nop
IL_0001: nop
IL_0002: ret
} // end of method WebForm1::TEST_SUB_BY_VAL
.method public instance void TEST_SUB_BY_REF(int32& i) cil managed
{
// Code size 3 (0x3)
.maxstack 8
IL_0000: nop
IL_0001: nop
IL_0002: ret
} // end of method WebForm1::TEST_SUB_BY_REF
The statement �ByVal is much better because ByRef is higher overhead because the data must be copied to the sub or function and then copied back once the sub or function completes.� is somewhat true in case of .NET V 1.0.
In .NET V1.1, The address of the ByRef variable(s) are copied at the call to the subprogram. Then the subprogram uses/modifies the variable that is in one, and only location, in memory. At the exit from the subprogram there is no copying back of the ByRef parameters.
So to reiterate�
When to USE BY VAL
By Val (by value) means that the called routine uses the value purely for input, to start a "one way" conversation. If A calls B (ByVal x), x becomes a temporary variable in B, using what A passed as a starting value. When B ends, so does x (and any changes made to it).
ByRef (by reference) means that the argument is a reference to the actual calling variable. If A calls B (ByRef x), B can change x and the changes are reflected in A. So, MySub4 (ByRef) changes g; MySub5 (ByVal) does not.
Using ByVal allows programmers to treat routines as "black boxes" that don't need to be opened. Parameters passed this way are "safe". If you don't plan to change the value of a parameter in your routine, you should use ByVal. It allows you to keep a smaller scope, and it saves maintenance time later when you have to read a routine to see if it affects the calling routine.
If you need to send a value back to the outer routine, consider using a Function instead of a Sub with ByRef.
When to Use ByRef?
There are some cases where ByRef is preferable. First, reference variable types (e.g. Forms, Textboxes, etc.) can't be processed with the ByVal model. ByVal t As Textbox doesn't cause a syntax error, but it gets processed as if ByRef was used (changes to t affect the actual textbox, not an in-memory copy). Specifying ByRef is clearer in this case. Arrays are also always treated as ByRef.
I am not a guru in Dotnet, This is my first article.
Any suggestion, Correction or feedback is most welcomed.
Thanks and regards,
Raj
devgeekraj@gmail.com