473,397 Members | 2,028 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,397 software developers and data experts.

Vb.NET: ByVal vs ByRef

Frinavale
9,735 Expert Mod 8TB
Hi there!

For the last few days I've been running my code through the code analyzer that comes with Visual Studio 2005. I've found a whole bunch of useful design recommendations produced by this tool but have been stumped by one of them.

One of the warning messages recommends that I consider designing my subs and functions so that they do not accept ByRef arguments.

One of my subs is meant to fill a DropDownList with values for the web page.
Since DropDownLists with the same options are found in more than one location I've created a Sub that:
-> accepts a DropDownList object,
-> clears the list,
-> and fills the list with values
-> If the DropDownList supplied does not exist it create a new DropDownList and fill that one.

Another of my functions returns true or false depending on if it executed correctly and also returns (ByRef) an object that has had 6 of its properties modified by the function.

From what I understood I need to use the ByRef means of passing the argument in order to correctly pass back the information that I've modified.

However, when I change the ByRef to ByVal, they still work properly.


Looking up the difference between ByRef and ByVal in the help file I've found that:
By Ref:
-> If the procedure has a genuine need to change the underlying element in the calling code, declare the corresponding parameter ByRef.

-> If the correct execution of the code depends on the procedure changing the underlying element in the calling code, declare the parameter ByRef. If you pass it by value, or if the calling code overrides the ByRef passing mechanism by enclosing the argument in parentheses, the procedure call might produce unexpected results.

ByVal:
-> If the underlying element is modifiable, but you do not want the procedure to be able to change its value, declare the parameter ByVal. Only the calling code can change the value of a modifiable element passed by value.


So, according to the help, an argument passed ByVal should not result in the calling code's variable being modified by the sub/function.

This Does Not appear to be the case.

I am Very confused.

Could someone please clarify?


Thanks a lot

-Frinny
Mar 26 '07 #1
9 17516
bplacker
121 100+
Byval is a way of passing parameters in by Value. This means that if you have 2 variables, a and b, and you pass them into a function with a=1 and b=2:

private sub function1(byval a as integer, byval b as integer)
a=50
b=60
end sub

Once you get out of this function, a will still be = 1, and b will still be = 2. If you were to use ByRef instead of byval... once you get out of the function a would b = 50 and b would be = 60.

Hope this helps.

By the way, passing parameters by reference is much more costly and time consuming than passing them by value.
Mar 26 '07 #2
RedSon
5,000 Expert 4TB
Hi there!

For the last few days I've been running my code through the code analyzer that comes with Visual Studio 2005. I've found a whole bunch of useful design recommendations produced by this tool but have been stumped by one of them.

One of the warning messages recommends that I consider designing my subs and functions so that they do not accept ByRef arguments.

One of my subs is meant to fill a DropDownList with values for the web page.
Since DropDownLists with the same options are found in more than one location I've created a Sub that:
-> accepts a DropDownList object,
-> clears the list,
-> and fills the list with values
-> If the DropDownList supplied does not exist it create a new DropDownList and fill that one.

Another of my functions returns true or false depending on if it executed correctly and also returns (ByRef) an object that has had 6 of its properties modified by the function.

From what I understood I need to use the ByRef means of passing the argument in order to correctly pass back the information that I've modified.

However, when I change the ByRef to ByVal, they still work properly.


Looking up the difference between ByRef and ByVal in the help file I've found that:
By Ref:
-> If the procedure has a genuine need to change the underlying element in the calling code, declare the corresponding parameter ByRef.

-> If the correct execution of the code depends on the procedure changing the underlying element in the calling code, declare the parameter ByRef. If you pass it by value, or if the calling code overrides the ByRef passing mechanism by enclosing the argument in parentheses, the procedure call might produce unexpected results.

ByVal:
-> If the underlying element is modifiable, but you do not want the procedure to be able to change its value, declare the parameter ByVal. Only the calling code can change the value of a modifiable element passed by value.


So, according to the help, an argument passed ByVal should not result in the calling code's variable being modified by the sub/function.

This Does Not appear to be the case.

I am Very confused.

Could someone please clarify?


Thanks a lot

-Frinny
Frin,

Look at it like this: The function is a black box
Expand|Select|Wrap|Line Numbers
  1. MyClass aClass = new MyClass
  2.  
  3. SetDataOn(aClass);
  4.  
  5. aClass = blackBox(aClass);
  6.  
  7. ShowDataToUser(aClass)
  8.  
In this example it doesn't matter if the blackBox passes aClass by reference or by value because blackBox returns aClass back to the caller. So what you have is the object going into the blackBox, the blackBox doing something to it, then the object comes out.

Now I will change it slightly:
Expand|Select|Wrap|Line Numbers
  1. MyClass aClass = new MyClass
  2.  
  3. SetDataOn(aClass);
  4.  
  5. int errorCode = blackBox(aClass);
  6.  
  7. ShowDataToUser(aClass)
  8.  
Now it matters if aClass is passed to blackBox by reference or by value. If it is by value then the system will make a copy of aClass and give it to blackBox to do stuff with. When blackBox returns *your* copy of aClass remains unchanged because a copy was created and the changes to the copy never carried over to *your* copy. If it is passed by reference then the system gives blackBox the address of the original copy so blackBox can go out to the memory location where the original aClass object lives and do stuff to it there. To say it another way, blackBox gets passed the original object to play with instead of a copy. So when blackBox finishes it not only changed your aClass object but it also returns some interesting error code data for you to play with.

Now this whole by value or by reference business can be quite complicated. In some languages the complier and system is not smart enough to copy everything properly if for example your class has some member data in it that is stored by reference then when the system copies it over it won't understand that those are reference parameters and it will treat them like data instead. You can get some weired stuff going on if that happens.
Mar 26 '07 #3
AricC
1,892 Expert 1GB
Frinny,
Easy way to think of ByRef and ByVal. ByVal passes a copy of the variable, ByRef passes the original.
Mar 27 '07 #4
Frinavale
9,735 Expert Mod 8TB
Frinny,
Easy way to think of ByRef and ByVal. ByVal passes a copy of the variable, ByRef passes the original.
Thank you all for your speedy replies!

You've all just assured me that ByVal and ByRef are supposed to work the way I thought the were supposed to. ByVal passing a Value and ByRef passing a reference to the memory location where the object is stored.

In my situation this does not appear to be the case.

The following is a watered down version of what is occuring in my code.
My question is why does object A in the MainClass.MainFunction() get set by the Utils.SetString() method:

Expand|Select|Wrap|Line Numbers
  1. Class MainClass
  2.   Private A as New MyClass 'say A has 6 Strings that need to be set if the object is validated against the database
  3.  
  4.   Sub MainFunction()
  5.       If Utils.SetStrings(A) then
  6.         ...
  7.       else
  8.         ...
  9.      end if
  10.   End Function
  11.  
  12. End Class
  13.  
  14. Class Utils
  15.     Public Function SetString(ByVal A as MyClass) As Boolean
  16.       Dim retval as Boolan
  17.       If CheckAgainstDatabase(A) = true Then 
  18.            A.String1="blaBla"
  19.            A.String2="blablablabla"
  20.            ...
  21.           retval = true
  22.         Else 
  23.           retval = false
  24.        End If
  25.  
  26.      Return retval
  27.     End Function
  28.  
  29.     Private Function CheckAgainstDatabase(ByVal A as MyClass) As Boolean
  30.           '...validates the object agains the database 
  31.     End Class
  32. End Class
  33.  
  34.  
At first I had Utils.SetString(ByRef A as MyClass)...then the code analyzer complained and for fun I changed it to ByVal...........I was Shocked when it worked properly and all my strings were set in the calling class!

-Frinny
Mar 27 '07 #5
Frinavale
9,735 Expert Mod 8TB
Frin,

...
Now it matters if aClass is passed to blackBox by reference or by value. If it is by value then the system will make a copy of aClass and give it to blackBox to do stuff with. When blackBox returns *your* copy of aClass remains unchanged because a copy was created and the changes to the copy never carried over to *your* copy. If it is passed by reference then the system gives blackBox the address of the original copy so blackBox can go out to the memory location where the original aClass object lives and do stuff to it there. To say it another way, blackBox gets passed the original object to play with instead of a copy. So when blackBox finishes it not only changed your aClass object but it also returns some interesting error code data for you to play with.

Now this whole by value or by reference business can be quite complicated. In some languages the complier and system is not smart enough to copy everything properly if for example your class has some member data in it that is stored by reference then when the system copies it over it won't understand that those are reference parameters and it will treat them like data instead. You can get some weired stuff going on if that happens.
Your reply was very informative.
This explains why the code analizer doesn't like me passing ByRef.
I've come from a C++ background and have an idea of how copy constructors and such work...I've never seen a copy constructor declared in a VB.NET project.

Is it even possible to declare a copy constructor in VB.NET?
It would be really useful because then you'd be able to avoid the memory-addresse-aka-pointers-aka-references stored in your object being treated incorrectly by specifically telling the compiler what to do...

I'm not storing any references in my object so I should be ok.

Thanks for the heads up!

-Frinny
Mar 27 '07 #6
RedSon
5,000 Expert 4TB
Thank you all for your speedy replies!

You've all just assured me that ByVal and ByRef are supposed to work the way I thought the were supposed to. ByVal passing a Value and ByRef passing a reference to the memory location where the object is stored.

In my situation this does not appear to be the case.

The following is a watered down version of what is occuring in my code.
My question is why does object A in the MainClass.MainFunction() get set by the Utils.SetString() method:

Expand|Select|Wrap|Line Numbers
  1. Class MainClass
  2.   Private A as New MyClass 'say A has 6 Strings that need to be set if the object is validated against the database
  3.  
  4.   Sub MainFunction()
  5.       If Utils.SetStrings(A) then
  6.         ...
  7.       else
  8.         ...
  9.      end if
  10.   End Function
  11.  
  12. End Class
  13.  
  14. Class Utils
  15.     Public Function SetString(ByVal A as MyClass) As Boolean
  16.       Dim retval as Boolan
  17.       If CheckAgainstDatabase(A) = true Then 
  18.            A.String1="blaBla"
  19.            A.String2="blablablabla"
  20.            ...
  21.           retval = true
  22.         Else 
  23.           retval = false
  24.        End If
  25.  
  26.      Return retval
  27.     End Function
  28.  
  29.     Private Function CheckAgainstDatabase(ByVal A as MyClass) As Boolean
  30.           '...validates the object agains the database 
  31.     End Class
  32. End Class
  33.  
  34.  
At first I had Utils.SetString(ByRef A as MyClass)...then the code analyzer complained and for fun I changed it to ByVal...........I was Shocked when it worked properly and all my strings were set in the calling class!

-Frinny
This might be an artifact of the way that strings are implemented in VB. Usually strings are buffer of characters. The buffer is usually an array. In VB the system probably takes care of setting the size of the buffer and resizing it as necessary, or there is some maximum that it will fail on if it gets to large.

Whats happening (I think) is that the system is treating strings as a special case and always passing by reference. Try doing the same thing with your above example but make the data in your class a char and see if that has the intended behavior.
Mar 27 '07 #7
RedSon
5,000 Expert 4TB
Ah Frin, you are in luck.

I found out the truth!

When the VB.NET and VB6 compilers compile your code it makes certain optimization decisions about the way your code will be processed at run time. One of these decisions is to determine if a variable should be placed on the stack or heap, the heap in .NET is now referred to as the managed heap. Variables placed on the heap are considered referenced variables and as such, VB will not create a second instance of a referenced variable, regardless of the ByVal qualifier. When the compiler encounters a variable declaration, it determines if it is a fixed length, most primitive data types are fixed lengths. If the variable is of a fixed length, it is determined that the variable will be stored on the stack. Otherwise it is considered a reference variable and placed on the heap.

The next question I would have is “What happens if I create a new local instance of the variable and assign the passed variable to it?”. You still get a reference. When the compiler encounters the assignment to a referenced variable it points it back to the original on the heap.

And since strings are dynamic, they are put on the heap.
Mar 27 '07 #8
Frinavale
9,735 Expert Mod 8TB
Ah Frin, you are in luck.

I found out the truth!

When the VB.NET and VB6 compilers compile your code it makes certain optimization decisions about the way your code will be processed at run time. One of these decisions is to determine if a variable should be placed on the stack or heap, the heap in .NET is now referred to as the managed heap. Variables placed on the heap are considered referenced variables and as such, VB will not create a second instance of a referenced variable, regardless of the ByVal qualifier. When the compiler encounters a variable declaration, it determines if it is a fixed length, most primitive data types are fixed lengths. If the variable is of a fixed length, it is determined that the variable will be stored on the stack. Otherwise it is considered a reference variable and placed on the heap.

The next question I would have is “What happens if I create a new local instance of the variable and assign the passed variable to it?”. You still get a reference. When the compiler encounters the assignment to a referenced variable it points it back to the original on the heap.

And since strings are dynamic, they are put on the heap.
I don't know why I wasn't informed in my Control Panel that these posts were here! It could have saved me some time.

I also found out the same thing! Except I have a different explanation of what's going on.

Essentially I didn't understand what a Reference Variable Type was and what a Value Type Variable was....its the same as the difference between what a native type is and what an object type is in other languages...for some reason .NET decided to do away with these common concepts and create new terms for them.

Anyways, Reference Variable types are any objects created from a Class and also include Arrays and Delegates.

Reference Variable types exist on the Heap whereas Value Variable types do not. This means that if you create an instance of a Reference Variable and then assign it to another variable you'll get a copy of the pointer to the memory location where the object exists on the Heap.

If you have a Value Variable and assign it to another variable you get a copy of its value...not a copy of the pointer.

Since Reference Variable types are any objects created from a Class, my custom objects are automatically Reference Variable types.

Now when I pass them into a function using ByVal I'm actually getting a copy of the Pointer to my object on the heap.

This explains why when I'm using ByVal my object in the calling function was being effected by the changes in my worker function.

This is also why the code analyzer was complaining when I was using ByRef...its because I was passing my function a pointer to my pointer.

I wish I had seen your posts earlier because they would also have cleared up my confusion about how things were working.

Thanks a lot for your help RedSon!

-Frinny
Mar 28 '07 #9
RedSon
5,000 Expert 4TB
Sure thing Frin, glad to be of service ;)
Mar 28 '07 #10

Sign in to post your reply or Sign up for a free account.

Similar topics

17
by: gokul | last post by:
Hi, Iam a newbie to dotnet and I experience problems in using the Browser control in VB .net. Though Iam able to use it with its basic features, I need to customise it. ...
8
by: Stephen Remde | last post by:
Hi, Private Declare Function CreateFile _ Lib "kernel32" Alias "CreateFileA" _ (ByVal lpFileName As String, _ ByVal dwDesiredAccess As Long, _ ByVal dwShareMode As Long, _ ByVal...
2
by: Nicola Garone | last post by:
Hi all I'm using VB.net. I need to define an object of type iShellFolder (since I have to call ShGetDesktopfolder API in Shell32.dll). I've created interop.Shell32.dll adding a reference to...
3
by: Paul | last post by:
I have been trying to code a callback in vb.net using the delegate method. I have successfully compiled the program and run it but after it accessess the copyfileex winapi method and then calls the...
1
by: Tom Edelbrok | last post by:
I have an old 32-bit DLL that is very necessary to our operation. It extracts data from a proprietary inudstrial database and gives it back to our VB6 programs. Everything works great under VB6. ...
3
by: bwalke | last post by:
I was wondering how the Process.Start() command can be used in a VB.NET Web Application. I have used this command in a Windows Application before successfully. I want the client side to envoke the...
2
by: evle | last post by:
haw to read data from an Infrared Infrared Remote Control
1
by: doc123 | last post by:
Hello, I am having trouble finding much information about how to implement Mailslots with VB.NET. This code works successfully when run on the same PC for all three steps: Create Mailslot, Write...
0
by: jwmaiden | last post by:
Hi, I'm trying to call a c++ dll from vb.net. My problem is in trying to figure out how to rewrite the parameters from c++ to vb. The original function in the dll is: void WINAPI...
5
by: sejal17 | last post by:
Hello Friends, I want Application that displays an image preview of a Word document (Like thumbnail View of word document) Following is my code but i got error on bold part of code ...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.