Byref and Byval

kamdickerson

New member
Joined
Oct 18, 2006
Messages
1
Location
U.S
Programming Experience
Beginner
Hello,
Ive just started working with vb .net and am having trouble distinguishing the difference between ByRef and ByVal. I know they are both used in the procedure header, but I don't know when to use them. :(
 
Basically.....

ByVal - Creates a copy of the object and passes it to the method.

Example

VB.NET:
Private Sub CleanMyHouse(byVal NumberOfRoomsToClean As Integer)
End Sub
 
 
Dim Rooms As Integer = 5
 
Me.CleanMyHouse(Rooms)


The Variable rooms is passed in as an argument when the method called. Byval then creates a copy of the variable or rather the value and passes it to the method CleanMyHouse. The NumberOfRooms parameter now holds the same value as the variable Rooms

ByRef - Using the same example as above, a copy is not created, but a pointer to the Rooms Variable in memory is passed.

So when passed ByVal if you alter the value of the NumberOfRoomsToClean argument the Rooms Variable remains unchanged. However if you pass it ByRef and you alter the value of the NumberOfRoomsToClean variable the Rooms variable will change also, because you will be changing the value where it is located in memory.

Becareful if you start passing things ByRef, infact i would avoid it if at all possible. The .Net way is Byval.

Thats the basics of it, however things change if you start passing objects that inherit from MarshallByRefObject and cross App Domain Boundries but we'll leave that for another time.
 
Mmmh, no - thats' not quite right. ByRef or ByVal, no copies of the object are created.. The original object exists always and only and they are always passed by reference. This does not mean they are always passed ByRef.

Without going into long and boring explanations, here is the rule in a nutshell:

ByRef and ByVal describe how the pointer to the object is passed, not how the object itself is passed.

A ByValled pointer can be repointed to something else without affecting what the original pointer points to. When a ByReffed pointer is changed to point to something new, the original pointer changes (because they are one and the same)




Now, here is the long and (maybe) boring explanation:

If we break this out into real world things that we know, I want you to picture a ball, a bit of string, and a paper tag.

When we write this:
Dim myBall as New Ball

we make a new ball (imagine having a ball in your hand) and we tie a bit of string to it, and we attach a label to the other end of the string and write myBall on it:
[myBall]---------(Ball)


When we pass this to a method like this:
Public Sub MyByValMethod(Byval b as Ball)

upon passing, a copy of the pointer is created and attached to the existing object. In our real world example we attached another bit of string and paper to our ball:
[myBall]---------(Ball)---------[b]

This b pointer will disappear and go out of scope when the Method finishes running, but until that time, it refers to the same ball.

Anything we do to the ball in this method, using the b pointer is reflected in the ball when the method exits, but if we point b to something else, another object is created:
Public Sub MyByValMethod(Byval b as Ball)
b = New Ball()

[myBall]---------(Ball)
[b]---------(New Ball)


Now, in the case of ByRef:
Public Sub MyByValMethod(ByRef b as Ball)

We dont create a new pointer and attach it to the ball (i.e. no extra bit of string and no new bit of paper), instead b and myBall are the same pointer:

[myBall / b]---------(Ball)

Still its the sam,e - any changes we make to the ball are kept, but the crucial upshot of this is that if we point b to a new ball, then when the method finishes and b goers out of scope, myBall will also be pointing to the new object.
b = New Ball()

[myBall / b]---------(New Ball)



Here's some code. Lets assume our ball is given a colour and an air-filled percentage when we make it:
VB.NET:
Public Class Ball
  Public Air as Integer
  Public Colour as String
 
  'constructor
  Sub New(ballColour as String, airPercent as Integer)
    Colour = ballColour
    Air = airPercent
  End Sub
 
  Public Sub TellMeAboutYourself()
    MessageBox.Show("I'm a " & colour & " ball and I have " & air & " air"
  End Sub
End Class
All our ball can do is be a colour and be inflated.

Lets make some methods that highlight some things:
VB.NET:
Public Sub DeflateBall_BR([B]ByRef[/B] b as Ball)
  b.Air = 0
End Sub
 
Public Sub DeflateBall_BV([B]ByVal[/B] b as Ball)
  b.Air = 0
End Sub
 
Public Sub ReplaceBall_BR([B]ByRef[/B] b as Ball)
  b = New Ball("blue", 100)
End Sub
 
Public Sub ReplaceBall_BV([B]ByVal[/B] b as Ball)
  b = New Ball("blue", 100)
End Sub

Now, we make a new ball:
VB.NET:
Dim myBall As New Ball("red", 100)
myBall.TellMeAboutYourself()
--> "I'm a red ball with 100 air"
 
DeflateBall_BV(myBall)
myBall.TellMeAboutYourself()
--> "I'm a red ball with 0 air"
If ByVal made a copy of the object, then the copied object would be deflated and the original would still be inflated. As it is the original is deflated, because we established another pointer to the original ball, and deflated using the new pointer (original ball)

This time, with ByRef:
VB.NET:
Dim myBall As New Ball("red", 100)
myBall.TellMeAboutYourself()
--> "I'm a red ball with 100 air"
 
DeflateBall_BR(myBall)
myBall.TellMeAboutYourself()
--> "I'm a red ball with 0 air"
Same result. We havent messed with where the pointer points, and we didnt copy any object data either.


Where things really happen with BR and BV is in making new balls:

VB.NET:
Dim myBall As New Ball("red", 100)
myBall.TellMeAboutYourself()
--> "I'm a red ball with 100 air"
 
ReplaceBall_BV(myBall)
myBall.TellMeAboutYourself()
--> "I'm a red ball with 100 air"
ReplaceBall made a new ball.. so where is it gone? Well, remember that BV makes a copy of the pointer. So what we did was get our original pointer and original ball. Make a new pointer and attach it to the original ball. Then we make a new ball and re-attach the new pointer to the new ball. Then we throw the new pointer and ball away leaving the originals untouched.

But with byref:
VB.NET:
Dim myBall As New Ball("red", 100)
myBall.TellMeAboutYourself()
--> "I'm a [B]red[/B] ball with 100 air"
 
ReplaceBall_BR(myBall)
myBall.TellMeAboutYourself()
--> "I'm a [B]blue[/B] ball with 100 air"
Our original pointer was reattached to the new object.


It should be noted that this is a very very dangerous and sometimes silly way to program. Be very sparing in your use of ByRef - if you ahve any methods that take an object in, create a new object based on it and you want to keep the new object, then do endeavour to have it as a return value from the method(function), not as a ByRef. Why? Because its not immediately obvious to another developer that any code you write will go and replace his lovely object that he passes into your method, with a new one.
If you went to the computer shop with your PC that your daughter had lovingly painted with nail varnish, and asked for it repaired, you might be upset if the guy gave you back a whole new system and said "but.. i copied the data over on the hard disk, isnt that enough?"
You put your PC in expecting some things to be changed inside but youd still get the same box back. ByRef might not give you the same box back, if that developer saw fit to do away with your box and give you another.

:)
 
That is way over complicating byref and byval, how on earth can you expect to educate someone who doesn't have an understanding of vb.net with a cryptic response like that. ByVal DOES in a basic sense, create a copy of the data, to say it doesn't is ridiculous. I refer you to the following article..

http://www.developerfusion.co.uk/show/1763/3/

Byref is a pointer to the memory location of the parameter passed, byval is not, if it is not then it HAS to be a copy/replica of the data, what else could it be? This isn't java or c++ it's .Net.
 
ByVal and ByRef refer to how a variable is passed as a parameter. A variable is not an object when the type is a class. When you pass a parameter ByVal you pass a copy of the variable, i.e. you are passing its value. When you pass a parameter ByRef you pass a reference to that variable.

The ramifications of passing ByVal and ByRef are quite simple. In almost all cases you should pass ByVal. This allows you to make changes to the object itself within the method and have them reflected in the caller. If you assign a new value to the argument within the method however, this will NOT be reflected in the caller. If you want to be able to assign a new value to the argument within the method and have that reflected in the caller then you must pass ByRef. So, both ByVal and ByRef can make as many changes as they like to the value passed in, but ByVal will always pass the same value back out again, while ByRef can pass out a completely different value if desired.
 
would passing variables/object byref be quicker than byval? it seems logical, since byval would need to go through the process of creating a copy of the variable, thus taking more time. but i might be forgetting something/missing something im not sure.

so, whats quicker, byref or byval?

regards
adam
 
byref is quicker because you are actually passing the memory location, becareful when using byref because the changes made by the calling procedure will change the variable. ByVal is more safer but consume more memory and slower because it have to copy itself.
 
There is absolutely no difference in speed between passing parameters ByRef or ByVal. In both cases you are simply creating a variable on the stack. As I said before, you should almost always be passing parameters ByVal unless you have a specific need to pass a different object back out via the argument,in which case you should pass ByRef. That should be the ONLY consideration. Try running this code:
VB.NET:
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    Dim str1 As String = "Original string 1"
    Dim str2 As String = "Original string 2"

    MessageBox.Show(str1)
    MessageBox.Show(str2)

    Me.PassByVal(str1)
    Me.PassByRef(str2)

    MessageBox.Show(str1)
    MessageBox.Show(str2)
End Sub

Private Sub PassByVal(ByVal str As String)
    'This change will NOT stick when the method completes.
    str = "String passed ByVal"
End Sub

Private Sub PassByRef(ByRef str As String)
    'This change WILL stick after the method completes.
    str = "String passed ByRef"
End Sub
 
That is way over complicating byref and byval, how on earth can you expect to educate someone who doesn't have an understanding of vb.net with a cryptic response like that. ByVal DOES in a basic sense, create a copy of the data, to say it doesn't is ridiculous.

ByVal does *NOT* create a copy of the data. To say it does is a mistruth, and given that youre trying to educate someone you have a responsibility to verify the accuracy of the informtion you pass to them.


If ByVal created a copy of the data then in this situation:
VB.NET:
[LEFT]Dim myBall As New Ball("red", 100)
myBall.TellMeAboutYourself()
--> "I'm a red ball with 100 air"[/LEFT]
 
[LEFT]DeflateBall_BV(myBall)
myBall.TellMeAboutYourself()
--> "I'm a red ball with 0 air"[/LEFT]
myBall would still say that it has 100 air. It does not. It says it has 0 air.

ByVal doesnt copy data, as evidenced by mutable objects retaining the changes they undergo when mutated by methods that they are passed to.


I refer you to the following article..

http://www.developerfusion.co.uk/show/1763/3/

Byref is a pointer to the memory location of the parameter passed, byval is not, if it is not then it HAS to be a copy/replica of the data, what else could it be? This isn't java or c++ it's .Net.

That article is part of a multi-part series where pointers are discussed in depth - I fail to see how it is fair to say my explanation is complicated, and then cite an article like that.

C++, java and .NET all work the same in this regard. Actually, in java, you cant pass things ByRef at all.

I'm trying to highlight the common misconception that ByVal and ByRef relate to how the object(data) is passed. They do not. They relate to how the object data's pointer is passed. I felt your explanation was an oversimplification leading to a mistruth.

If you read the other responses about "which is faster" we can see that there is a very common misconception about this, and the incorrect "object's data is cloned" notion is too widely held.
 
Last edited:
A quote from that article.

Selecting a ByVal would thereby mean you are only working on a copy or replica of the data, and not the actual data segment it self.

I'll thankyou not to call me a liar, and i suggest that you do some research.

C++ and .Net are the same in this regard?

Preposturous!
 
so, whats quicker, byref or byval?

Take a look again at the example explanation I posted about strings and balls - we never make a copy of the ball, and establishing a new pointer to an existing ball is very fast. As noted, it is the pointer that is cloned, not the object data itself.

byref is quicker because you are actually passing the memory location, becareful when using byref because the changes made by the calling procedure will change the variable. ByVal is more safer but consume more memory and slower because it have to copy itself.

I'm sorry to say that nearly every statement in your post is incorrect. You talk about memory locations etc so youre clearly more interested in the low level than most people would be.

In .NET we have two areas for data. The stack, and the heap. Primitive (value) types like ints and booleans live entirely on the stack. Reference types (Objects) live on the heap. When a new object is made and placed on the heap, a primitive (e.g. a long) is placed on the stack, holding the numerical memory address where the object may be found in the heap. It is thus said to be a reference type, because it is accessed by a reference. We have a name, myBall and this is known to be an long on the stack that holds a memory address of an object on the heap. We dont have direct access to the heap, we must first lookup where it lives by reading the contents of the variable on the stack. This is why it is a reference type, not a value type. It wouldnt be efficient to store value types on the heap because they are small enough to live on the stack and thus need no double leg from stack to heap.

When we pass that reference object to a method ByVal, the primitive value (pointer) on the stack is cloned and another pointer thus created on the stack, pointing to the object on the heap. If we re-point this pointer somewhere else, the original primitive remains pointing to the original object on the heap, and the cloned pointer now points to a new object on the heap.
When we pass something ByRef we do not make a clone of the pointer on the stack, we just reuse the same pointer. Thus, changing what this pointer points to (making a new object on the heap) changes what the original pointer points to.

One of the achilles heels with the ByRef/ByVal explanations is that people ask about strings. They say "When I pass a string ByVal it doesnt get changed, but when I pass it ByRef it changes/changes are retained"
The problem with citing string as an example (apologies to Mr McIlhinney, though I'm not bashing his explanation) is that strings are immutable; once created they cannot be changed. You may create a different string that is an altered version of the first, but the string content itself cannot change.

Thus people say that they pass their strings ByRef to retain changes to them - no, what actually happens is that the method that "alters" the string actually goes and creates a whole new string object on the heap, and points the old pointer to the new object. It *looks* like the string has changed content, but it has actually changed to a completely new string object.
Of course, because ByVal copies the pointer, any re-pointing of the copied pointer is lot when scope returns to the original.

Ends up, try not to use strings when creating examples that demonstrate mutating the object itself. Using strings to demonstrate a change to a whole new object is fine.

In my example you'll note I deliberately created a mutable object: we can deflate and inflate the ball. In either case of ref or val, the ball remained deflated after the method had finished.


As others have noted, do not use ByRef, until you fully appreciate what is going on with it. OO programs should be written such that objects do not fiddle with other object's data (my ball example should not directly fiddle with the air content.. it should call a method asking the ball to deflate) and that includes swapping the object for another object entirely


The situations where ByRef is necessary are rare, but an example exists in Double.TryParse
You make the variable pointer, then pass it to tryparse. The return value tells whether the conversion succeeded, and the passed variable is the result. Double.TryParse could not be established with ByVal:

Dim emptyDoublePointer As Double 'no object created, just a pointer
Double.TryParse("1234", emptyDoublePointer...)
MessageBox.Show(emptyDoublePointer.ToString())
--> 1234

String.Format works byval. We have to say:

Dim myUnfilledString as String = "I was filled with {0}"
Dim myFilledString As String = String.Format(myUnfilledString, "1234")
MessageBox.Show(myUnfilledString)
--> "I was filled with {0}"
MessageBox.Show(myFilledString)
--> "I was filled with 1234"

In this case we've had to capture the return value because String.Format takes its input string ByVal. If it took it byref it would re-point our original string. That might not be what we want if we want to re-use the unfilled string! Mcrosoft didnt use ByRef though they could have, and I'm glad they didnt because they would have been fiddling my original strings!



Actually, this has prompted a question in me. What happens if we pass a ReadOnly pointer as a ByRef argument (either directly or indirectly)? The compiler should disallow it, no?
 
Last edited:
A quote from that article.
I'll thankyou not to call me a liar, and i suggest that you do some research.

My post did create this impression and I hope you can accept my apology as it was not my intention to assert you to be a liar. I've amended the wording of my post, but I will do so again if you feel it is still calling you. Sorry again. :/

Try the code examples for yourself. If youre working on a copy of the data then the original ball will remain inflated, unless you assert that the changed copied data is copied back over the original.. what a waste of time!

The guy who wrote that article youre citing, is wrong too.. Dont take his opinion blind jsut because he's published an article; do your own research!

I dont know how you'd get VB to print the address on the heap of the object data but pass something ByVal, and look at the memory address on the heap of both the original pointer and the new pointer (within the method scope) - they will be the same address indicating the data wasnt copied anywhere


Preposturous!

All OO languages adopt the same notions of stacking/heaping and hence the same connotations of passing the stack pointers byref or byval
 
Last edited:
Apology accpeted. :) I think that you will find that is only the case if you are passing a reference type. A value type will be copied. The bases classes responsible for this are..

MarshallByRefObject

MarshallByValueObject

Of course, if you have a Dataset with 100,000 rows and you pass it byval it won't do a byte by byte copy to a different memory location. But if you were to pass a value type a copy of the argument would be created and passed to the parameter in the sub or function called.
 
As I have already stated, ByVal DOES create a copy, but a copy of the VARIABLE, not the OBJECT. If the variable is a value type then creating a copy of the variable IS creating a copy of the data. If the variable is a reference type then it is NOT, but rather just creating a copy of the reference. This new reference still refers to the same object as the original, thus any changes made to the object via the new reference will be reflected in the original, but assigning a new object to the new reference simply means assigning a new memory address to it. This has no effect on the original reference, which still contains the original memory address.

ByVal and ByRef refer to how stack variables are treated, not heap objects.
 
There is absolutely no difference in speed between passing parameters ByRef or ByVal. In both cases you are simply creating a variable on the stack. As I said before, you should almost always be passing parameters ByVal unless you have a specific need to pass a different object back out via the argument,in which case you should pass ByRef. That should be the ONLY consideration.
You are right and you are consequently wrong.. there is no speed difference about ByVal and ByRef parameters. The difference is how these often are used to choose between a Sub method or a Function method. When using ByRef one usually make it a Sub method and when using ByVal one similary have to make it a Function method to get the return. A Function method declares and allocates a return value and Sub method does not, so in these cases the difference is this declaration and allocation of a variable. For processing intensive loops the speed difference of calling a ByReffed Sub method and a ByValled Function method can be significant. This is noteworthy but however special cases.

By the way cjard, I liked the new words 'ByReffed' and 'ByValled' :)
 
Back
Top