|
-
May 31st, 2007, 04:27 AM
#1
Thread Starter
Frenzied Member
[2005] BYVAL v BYREF
This thread is a continuation of this one which got off the topic.
http://www.vbforums.com/showthread.p...60#post2897060
With reference types, is there any advantage using ByVal and any disadvantage using ByRef?
I was so used to using ByRef in VB6 as it was the default that I have continued to use it as the default unless I specifically want to pass ByVal - that is when I don't want the value of the passed variable to be changed.
What was MS's rationale for changing the default to ByVal?
-
May 31st, 2007, 04:33 AM
#2
Fanatic Member
Re: [2005] BYVAL v BYREF
You already got your answer, making the default to ByVal is just a matter of choice (I assume that the parameters most of the time keep their value when exiting a procedure). If you want your parameters to be changed when exiting a sub or a function, pass them by reference then. Ok it gives you some extra work but, hey man, nothing comes for free.
-
May 31st, 2007, 04:37 AM
#3
Re: [2005] BYVAL v BYREF
I can't tell you exactly what the creators were thinking, but in general you should provide as little access to everything as possible. If class-level access is not required to a variable then it should be declared locally. If public access is not required to a member then it should be declared private. If write access is not required to a property then it should be declared read-only. If the value of a variable doesn't need to be changed within a method then it should be passed by value.
There is no benefit to passing a parameter by reference if you don't need to change it. Either way a reference has to be created. Whether it's a copy of the original reference or a reference to the original reference makes no meaningful difference to your application. The only difference is whether or not the value fo the variable can be changed. If the value is not supposed to change then don't allow it to be: pass it by value.
Because ByVal is the default for VB.NET you simply omit both and the IDE will insert it. Only if you need to change the value of the variable should specify ByRef.
-
May 31st, 2007, 04:38 AM
#4
Thread Starter
Frenzied Member
Re: [2005] BYVAL v BYREF
My question is this:
If ByRef was considered to be the default of choice in VB6, what has changed in VB.NET for ByVal to now be considered the default of choice?
-
May 31st, 2007, 04:44 AM
#5
Re: [2005] BYVAL v BYREF
Further, how often do you actually change the value of a parameter in a method? I'm not talking about setting a property of the parameter, I'm talking about assigning a completely new value to the parameter that you want to stick after the method completes? That situation is in a very small minority, so it makes sense that passing by value should be the default. I only pass a parameter by reference if I have to and I would have several hundred parameters passed by value for every one passed by reference.
As I said, it is considered good practice to provide no more access to anything than is required. VB has never had a reputation of being the first choice of programming language for those who prize good practice. Perhaps that's the motivation for the change.
-
May 31st, 2007, 04:49 AM
#6
Thread Starter
Frenzied Member
Re: [2005] BYVAL v BYREF
 Originally Posted by jmcilhinney
I can't tell you exactly what the creators were thinking, but in general you should provide as little access to everything as possible. If class-level access is not required to a variable then it should be declared locally. If public access is not required to a member then it should be declared private. If write access is not required to a property then it should be declared read-only. If the value of a variable doesn't need to be changed within a method then it should be passed by value.
There is no benefit to passing a parameter by reference if you don't need to change it. Either way a reference has to be created. Whether it's a copy of the original reference or a reference to the original reference makes no meaningful difference to your application. The only difference is whether or not the value fo the variable can be changed. If the value is not supposed to change then don't allow it to be: pass it by value.
Because ByVal is the default for VB.NET you simply omit both and the IDE will insert it. Only if you need to change the value of the variable should specify ByRef.
OK. Case closed. So it's a matter of best design practice. Coming from a VB6 background, my philosophy has been the opposite of "Only if you need to change the value of the variable should you specify ByRef". That is, "only if you don't want the value of the variable to be changed should you specify ByVal".
-
May 31st, 2007, 04:56 AM
#7
Re: [2005] BYVAL v BYREF
Would that go along with the philosophy of "only if you don't want the value visible everywhere should a variable not be declared globally"? One is a more extreme example but the principle is the same.
-
May 31st, 2007, 05:00 AM
#8
Thread Starter
Frenzied Member
Re: [2005] BYVAL v BYREF
 Originally Posted by jmcilhinney
Further, how often do you actually change the value of a parameter in a method? I'm not talking about setting a property of the parameter, I'm talking about assigning a completely new value to the parameter that you want to stick after the method completes? That situation is in a very small minority, so it makes sense that passing by value should be the default. I only pass a parameter by reference if I have to and I would have several hundred parameters passed by value for every one passed by reference.
As I said, it is considered good practice to provide no more access to anything than is required. VB has never had a reputation of being the first choice of programming language for those who prize good practice. Perhaps that's the motivation for the change.
I would rarely change the value of a parameter in a method but to me, this adds weight to the argument that using ByRef does not cause problems. That is, if you don't often change values in methods then there is limited opportunity for ByRef to cause a problem. However, I know what your answer will be - why leave any opportunity for ByRef to cause an issue with a variable that was inadvertently and incorrectly changed.
-
May 31st, 2007, 05:10 AM
#9
Re: [2005] BYVAL v BYREF
 Originally Posted by robertx
I know what your answer will be - why leave any opportunity for ByRef to cause an issue with a variable that was inadvertently and incorrectly changed.
Exactly. There are two schools of thought:
1. Leave everything open by default and only close what specifically needs to be closed.
2. Leave everything closed by default and only open what specifically needs to be opened.
Both can be used without any issues in any specific case, but overall the second option will lead to fewer issues. VB has always had a reputation as being a fairly lax language and this is just one example of why. The thinking has been that you make everything open by default and then the dunces will hit fewer roadblocks and be more inclined to keep using the langauge. That attitude has also let the dunces drive off more cliffs as a result. The C/C++ fraternity's attitude has long been that the dunces shouldn't be coding anyway. Note that I'm not saying that VB6 coders are dunces. I'm saying that VB6 made it easier for a dunce to be a coder. VB.NET does so too, although it has tightened up in comparison to VB6. Again, the switch to a default of ByVal rather than ByRef is an example of this.
-
May 31st, 2007, 05:47 AM
#10
Thread Starter
Frenzied Member
Re: [2005] BYVAL v BYREF
I also had the idea that using ByVal is poor from a memory management point of view. That is, why unnecessarily create copies of objects which use memory when you can just pass the object itself? Years ago, I remember having what seemed to be a memory leak with a VB6 application. The problem disappeared when I changed an MSComm control parameter from ByVal to ByRef. The procedure was called repeatedly in the application.
-
May 31st, 2007, 05:53 AM
#11
Re: [2005] BYVAL v BYREF
I never used VB6 myself so I don't know the finer points of how it worked. Maybe it actually did copy entire objects when passing by value. VB.NET definitely does not, at least not with reference type objects anyway. That could be a very good reason for the change in the default method of passing parameters. With value type objects it does create a copy of the entire object when passing by value but you aren't supposed to define large structures anyway so that shouldn't be an issue. If a structure is large enough to cause issues when passed by value then it should be a class.
-
May 31st, 2007, 06:22 AM
#12
Frenzied Member
Re: [2005] BYVAL v BYREF
In this post:http://www.vbforums.com/showthread.p...60#post2897060 RobertX Wrote:
In both cases the message box displayed "100" which is consistent with what you have described. Given that the outcome is the same, is there any advantage using ByVal and any disadvantage using ByRef in this instance?
To which you received this reply:
You should always pass everything by value unless you specifically want the value of the variable being passed to be changed. Note that I said "the value of the variable". If the variable is a reference type then the value it contains is the memory address of an object. Only if you want to be able to pass out a different object to what was passed in should you pass by reference.
An example of when the called procedure would actually be meant to (on purpose) change the passed reference variable (by Reference) would be like this:
Code:
Sub RemoveOriginalReference(byRef OriginalReferenceVariable as Thing)
If OriginalReferenceVariable IsNot Nothing Then
OrigianalReferenceVariable = Nothing
End If
End Sub
That isn't an example of "Only if you want to be able to pass out a different object to what was passed in should you pass by reference."
But it does show how you can mess with the original object variable if it's been passed by reference.
So, as previously stated by JM, only if you intend on modifying the passed pointer itself would you pass by reference.
You also asked "why did microsoft make the change". I also don't know their thinking, but you'll notice that alot of what they are doing is aligning various aspects of different languages so that the languages are more consistant with each other. Perhaps that could be a reason. Or perhaps they are making that move now to support other planned changes in the future.
It doesn't matter though unless you are moving from VB6 to VB (verison later) because the internal workings are the same; The only difference being the default whether it's byVal or byRef.
-
May 31st, 2007, 08:24 AM
#13
Fanatic Member
Re: [2005] BYVAL v BYREF
I used to use ByRef (in C, mind you) when I began programming in situations where I had a function that would, say, square a number. I would use
square(a)
But, as I began using better programming practices, I stopped passing parameters by reference and instead began returning values.
a = square(a)
where square would return an integer, and a was passed by value.
It just seems to me, that once you begin following good programming practices, the need for ByRef becomes very small.
VB.Net 2008
.Net Framework 2.0
"Must you breathe? 'Cause I need heaven..."
-
Nov 14th, 2007, 12:19 AM
#14
Thread Starter
Frenzied Member
Re: [2005] BYVAL v BYREF
Further to this discussion, I have discovered something interesting. A reference type can be made to behave like a value type if the passed object is reinitialised in the procedure that calls it. That is, if you pass a reference type to a procedure ByVal and reinitialise it before it is modified, the object that is returned to the calling procedure will be identical to the one that was passed. The object that is returned to the calling procedure will be the object at the time of reinitialising.
This example demonstrates:
Code:
Private Sub RefTypeTest()
Dim ht As Hashtable
ht = New Hashtable
ht.Add("1", "1")
RefTypeByVal(ht)
MsgBox("The hash table has 2 items. The '1/1' and '2/2' key pair values were returned. The 3/3 key pair value was lost.")
ht = New Hashtable
ht.Add("1", "1")
RefTypeByRef(ht)
MsgBox("The hash table has only 1 item . The 3/3 key pair value was returned. The '1/1' and '2/2' key pair values were lost.")
End Sub
Private Sub RefTypeByVal(ByVal ht As Hashtable)
ht.Add("2", "2")
ht = New Hashtable
ht.Add("3", "3")
End Sub
Private Sub RefTypeByRef(ByRef ht As Hashtable)
ht.Add("2", "2")
ht = New Hashtable
ht.Add("3", "3")
End Sub
My question is - how do you know whether an object is a reference type or a value type?
-
Nov 14th, 2007, 12:44 AM
#15
Re: [2005] BYVAL v BYREF
No, reference type objects cannot be made to behave like value type objects under any circumstances. All variables are stored on the stack. Value type variables contain a value, i.e an object itself, while reference type variables contain a reference, i.e a memory addres, which is a pointer to the actual object stored on the heap. That is the difference between value types and reference types, plain and simple, and that never changes. The net result of some operations on a value type and a reference type may be the same but they will never behave the same because they never are the same.
Structures are value types and classes are reference types.
-
Nov 14th, 2007, 01:05 AM
#16
Re: [2005] BYVAL v BYREF
A bit 'slightly' off topic but how come some ByVal parameters in vb6 API declarations have to be ByRefs in .net and vice versa?
-
Nov 14th, 2007, 01:28 AM
#17
Thread Starter
Frenzied Member
Re: [2005] BYVAL v BYREF
 Originally Posted by jmcilhinney
No, reference type objects cannot be made to behave like value type objects under any circumstances. All variables are stored on the stack. Value type variables contain a value, i.e an object itself, while reference type variables contain a reference, i.e a memory addres, which is a pointer to the actual object stored on the heap. That is the difference between value types and reference types, plain and simple, and that never changes. The net result of some operations on a value type and a reference type may be the same but they will never behave the same because they never are the same.
Structures are value types and classes are reference types.
The challenge was to pass a reference type to a procedure, modify it and return the original value to the calling procedure.
I assume that when you pass a reference type to a procedure ByVal and reinitialise it that the passed copy of a pointer to the object is now pointing to a new object of the same type rather than the object to which it was pointing when it was passed. Therefore, the object can be modified whilst the original object remains intact.
-
Nov 14th, 2007, 01:43 AM
#18
Re: [2005] BYVAL v BYREF
 Originally Posted by robertx
The challenge was to pass a reference type to a procedure, modify it and return the original value to the calling procedure.
I assume that when you pass a reference type to a procedure ByVal and reinitialise it that the passed copy of a pointer to the object is now pointing to a new object of the same type rather than the object to which it was pointing when it was passed. Therefore, the object can be modified whilst the original object remains intact.
You start off with one variable and one object. Let's call them var1 and obj1, so var1 contains the memory address of obj1. You call a method with an argument declared ByVal. The system creates a copy of var1 and that becomes that parameter in the method. You've now got var1 and var2, both containing the memory address of obj1. If you now create a new object and assign it to the parameter you've got var1 containing the memory address of obj1 and var2 containing the memory address of obj2. Any property value changes you make in the method are done through var2, so they affect obj2. Once the method completes control is returned to the calling method where var1 still refers to obj1. No changes were made in the method to obj1.
Now lets say that you call a method with an argument declared ByRef. The system creates a reference to var1 rather than a copy of it. You now have var2, which contains a reference to var1, which contains a reference to obj1. If you now create a new object and assign it to the parameter you are assigning obj2 to var2. var2 is a reference to var1, so obj2 gets assigned to var1. var1, which is the original variable, now refers to obj2, a different object to what it referred to before.
-
Nov 14th, 2007, 02:25 AM
#19
Thread Starter
Frenzied Member
Re: [2005] BYVAL v BYREF
The ByVal explanation is straightforward but the ByRef bit is a little more challenging.
I don't quite follow this:
 Originally Posted by jmcilhinney
If you now create a new object and assign it to the parameter you are assigning obj2 to var2.
In the ByVal scenario, when we create a new object, the var2 reference shifts from obj1 to obj2.
In the ByRef scenario, we are passing a pointer to a pointer. When we create a new object, if var2 is now pointing to obj2 then how can it be also pointing to var1?
-
Nov 14th, 2007, 07:40 AM
#20
Re: [2005] BYVAL v BYREF
But var2 is NOT pointing to obj2. As you said yourself, var2 is a pointer to a pointer, so you cannot assign the memory address of an object to var2. The system is mart enough to know that the var2 refers to var1 no matter what, and the new object's memory address gets stored in var2.
-
Nov 14th, 2007, 08:24 AM
#21
Re: [2005] BYVAL v BYREF
 Originally Posted by robertx
What was MS's rationale for changing the default to ByVal?
At a guess, standardisation with the other first class Framework languages.
 Originally Posted by jmcilhinney
I never used VB6 myself so I don't know the finer points of how it worked. Maybe it actually did copy entire objects when passing by value.
No, its reference/value semantics are exactly like VB.NET.
-
Nov 14th, 2007, 09:18 AM
#22
Thread Starter
Frenzied Member
Re: [2005] BYVAL v BYREF
 Originally Posted by jmcilhinney
But var2 is NOT pointing to obj2. As you said yourself, var2 is a pointer to a pointer, so you cannot assign the memory address of an object to var2. The system is mart enough to know that the var2 refers to var1 no matter what, and the new object's memory address gets stored in var2.
If, in both cases, we start with a var1 pointer (to an obj1 object).
In the ByRef case, is another reference (var2) actually created or is var1 itself passed to the procedure while it is still pointing at obj1?
If var1 points to obj1 and then a new object is created (obj2) to which var1 now points, where does var2 come into this equation?
-
Nov 14th, 2007, 05:32 PM
#23
Re: [2005] BYVAL v BYREF
 Originally Posted by robertx
If, in both cases, we start with a var1 pointer (to an obj1 object).
In the ByRef case, is another reference (var2) actually created or is var1 itself passed to the procedure while it is still pointing at obj1?
If var1 points to obj1 and then a new object is created (obj2) to which var1 now points, where does var2 come into this equation?
I thought I'd already eplained this twice. Let's use the term pointer instead of reference, because that's what they are under the hood anyway. A reference type variable is a pointer. When you pass a reference type variable by value the variable is copied, so you have two pointers containing the same memory address. If you assign a different memory address to one the other still contains the old memory address.
When you pass a reference type variable by reference and new pointer is created that contains the memory address of the variable that contains the memory address of the object. When you assign a new object to that second variable, the system is smart enough to know that it's a pointer to a pointer. The system does NOT assign the memory address of the object to the new variable. It assign the memory address of the object to the first variable, which the second variable points to.
.NET is all strongly typed. If a variable's type is a pointer to a pointer then that variable can only ever contain the address of another pointer. It can NEVER contain the memory address of an object.
-
Nov 14th, 2007, 05:56 PM
#24
Re: [2005] BYVAL v BYREF
Pointers, and pointers to pointers, have always been such a difficult subject that entire books have been written about just that subject alone. One of the difficulties I expect people to have with .NET is that a variable that contains a class:
dim obj1 as New SomeObjClass
is not what it looks like. Obj1 is not an instance of SomeObjClass, but is a four byte (on 32 bit systems) value that holds the object of an instance of the SomeObjClass. Thus, when you pass obj1 somewhere, or copy it to another object, you aren't copying the members and all the hoopla associated with the object, you are just passing those four bytes, or copying those four bytes, regardless of the size of the actual object.
People often talk about obj1 as if it was the object itself, which in most cases is close enough to the truth as makes no difference, but when you get into copying and passing objects as arguments, that is where the distinction between the concept and reality starts becoming important.
By the way, where did this quesion come from at its base? In both VB6, and .NET, there is a default qualifier for all arguments. Which of those two (ByRef and ByVal) was the default switched between the two programs, but I'd really have to think about it to remember which was which.
In C, there are some advantages if the compiler can assume that an argument will never change. Because of that, you can declare an argument as const, which has no real impact on your coding, but is an advantage for the compiler. I would say that passing everything ByVal, and coding as if every argument was a constant is a good default practice, though I have no idea whether there is still a compiler advantage in VB.NET as there was in c. The other reason to do this, which you see in many books on good coding technique, is that changing your arguments when they are ByRef is a side effect of a function, and side effects generally obscure the intent of a function, which makes code harder to maintain. Therefore, only use ByRef when you want to clearly indicate your expectation that the variable in question WILL be changed by function.
If you follow those guidelines, then ByVal vs. ByRef almost goes away. Since I started with those guidelines when I got into VB6, the default ByRef was an annoyance to me, but I simply ignored it because by habit I never altered my arguments. Keep in mind that that is not the same as never altering your opinions. The former makes you a better coder, while the latter makes you president.
My usual boring signature: Nothing
 
-
Nov 14th, 2007, 08:33 PM
#25
Thread Starter
Frenzied Member
Re: [2005] BYVAL v BYREF
Got it. This is the bit that I missed:
 Originally Posted by jmcilhinney
.NET is all strongly typed. If a variable's type is a pointer to a pointer then that variable can only ever contain the address of another pointer. It can NEVER contain the memory address of an object.
So what actually happens to obj1 when var1 now points to obj2?
-
Nov 14th, 2007, 09:20 PM
#26
Re: [2005] BYVAL v BYREF
 Originally Posted by robertx
Got it. This is the bit that I missed:
So what actually happens to obj1 when var1 now points to obj2?
Nothing. Let's say that you have a Person class and that class has a Car property. I'm a Person object and my Car property refers to a Car object. If I buy a new car my Car property now refers to a new object. What happens to the old object? Nothing, that's what. It's no longer referred to by my Car property is all. If my partner was sharing the car with me then her Car property still refers the original car.
Are you starting to get the idea that Object-Oriented Programming is so-called because it is modelled on real-world objects? If you want to understand an OOP concept then just look at the real world and 99% of the time it will show you.
-
Nov 14th, 2007, 09:29 PM
#27
Thread Starter
Frenzied Member
Re: [2005] BYVAL v BYREF
Yes. That's a good way of looking at it.
obj1 is now occupying memory when it no longer serves any purpose and won't be used again. To draw the analogy, your car is irreparable and is ready for the scrap heap. You wouldn't want that car just sitting on your front lawn - you would want to get rid of it. I assume that this is where the .NET garbage collector comes in?
-
Nov 14th, 2007, 09:40 PM
#28
Re: [2005] BYVAL v BYREF
 Originally Posted by robertx
Yes. That's a good way of looking at it.
obj1 is now occupying memory when it no longer serves any purpose and won't be used again. To draw the analogy, your car is irreparable and is ready for the scrap heap. You wouldn't want that car just sitting on your front lawn - you would want to get rid of it. I assume that this is where the .NET garbage collector comes in?
That's correct. Once there are no more people using that Car it's available to the garbage collector. The way the GC works though, the Car will just sit where it is until the space it's occupying is needed by another object. That's why disposing objects is so important. If that unused Car contains usable parts they will just sit there unavailable to anyone until the wrecker comes to collect it. In this case removing those usable parts when you don't need the car any more is equivalent to disposing the object to release system resources.
-
Nov 14th, 2007, 09:45 PM
#29
Thread Starter
Frenzied Member
Re: [2005] BYVAL v BYREF
When you say "disposing objects is so important", do you mean setting them to Nothing or calling the Garbage Collector?
-
Nov 14th, 2007, 09:51 PM
#30
Re: [2005] BYVAL v BYREF
If the unused object is using some kind of limitted system resource such as a pen, or perhaps a database connection, then you would want to clean it up. Setting a variable to Nothing will not actually do anything, because a variable is just the address of the object in memory, and by setting the variable to nothing, you change the contents of the variable from the address to 0. The object itself is not touched by that.
You CAN call the garbage collector explicitly, but there is rarely a need to do that. Let it run on it's own. What JM was refering to is that you should call Dispose on any object that implements it.
My usual boring signature: Nothing
 
-
Nov 14th, 2007, 09:57 PM
#31
Thread Starter
Frenzied Member
Re: [2005] BYVAL v BYREF
This is starting to get off topic so I have started a new thread here:
http://www.vbforums.com/showthread.p...44#post3057944
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|