PassingByVal / ByRef

dugdugdug

Active Member
Joined
May 11, 2012
Messages
342
We know the default to pass simple variable args is ByRef, so you never need to write ByRef, unless you want to be specific.

What about object variables?

According to this article by Chip Pearson, he states objects are ALWAYS passed ByRef:

Passing Variable ByRef And ByVal

Does he mean the DEFAULT is ByRef or does he mean it can ONLY be passed ByRef?

In a class, if you inserted a property using Insert - Procedure - Property, you get the following:

Code:
Public Let Property (ByVal MyVar) As SomeType

But some books omit the keyword ByVal, so are they he same, ie the default is ByVal? (If you added ByRef instead, does it make a difference)?

Similarly for the Set Property, if you added ByVal, or ByRef or omitted it altogether, what's the difference?

Thanks
 
Last edited:
Hi Rory

I believe you can, as long it is a dynamic array, like in Get.

Hi Pedro,

Yes - you are correct. That's interesting - obviously either the array is copied and then the copy passed, or you can in fact pass an array ByVal contrary to the VBA documentation.
 
Upvote 0

Excel Facts

Wildcard in VLOOKUP
Use =VLOOKUP("Apple*" to find apple, Apple, or applesauce
dugdugdug said:
Are these three all the same:

Code:
Property Let MyVar(ByVal MyVa As SomeType)
Property Let MyVar(ByRef MyVa As SomeType)
Property Let MyVar(MyVa As SomeType)

Yes, they are. A Property Let procedure will not accept a parameter by reference, even if you declare it to.
likewise for these three:

Code:
Property Set MyVar(ByVal MyVa As SomeType)
Property Set MyVar(ByRef MyVa As SomeType)
Property Set MyVar(MyVa As SomeType)

Yes they are also the same. Property Set behaves like Property Let.

For Property Get procedures, however, they would not be the same. Property Get routines adhere to the usual rules for routines in that ByRef is the default.

So what happens if you pass an array via property?

It turns out, as Pedro said, that you can pass an array to a Property Let as long as it was declared as a dynamic array. However, it behaves as if passed ByVal, so I can only assume (pending further research) that it is copied and that copy is passed.
 
Upvote 0
Found this on the web, hope it helps:


Lets' look at what happens with a regular function.

Start with a string.

Code:
 Dim varDef As String, varRef As String, varVal As String
 varRef = "ref"
 varVal = "val"
 varDef = "default"

 testVar varDef, varRef, varVal
 Debug.Print varDef, varRef, varVal

being passed to this function as a variant...

Code:
Private Function testVar(varDef As Variant, ByRef varRef As Variant, ByVal varVal As Variant)
 varDef = "overwrote default"
 varRef = "overwrote ref"
 varVal = "overwrote val"
End Function

If the string was passed by reference, then it will be changed. If by value it will remain unchanged.. the result is...

overwrote default overwrote ref val

which proves that default & by reference are the same,

So let's do the same thing with arrays...

Code:
 Dim arrDef(1 To 1) As String
 arrDef(1) = "arr string default"


 Dim arrRef(1 To 1) As String
 arrRef(1) = "arr string ref"

 Dim arrVal(1 To 1) As String
 arrVal(1) = "arr string val"

 testArray arrDef, arrRef, arrVal
 Debug.Print arrDef(1), arrRef(1), arrVal(1)

Private Function testArray(varDef As Variant, ByRef varRef As Variant, ByVal varVal As Variant)
 varDef(1) = "overwrote string default"
 varRef(1) = "overwrote string ref"
 varVal(1) = "overwrote string val"
End Function

the result is...
overwrote string default overwrote string ref arr string val

which means that arrays behave the same as regular args..

So what happens when we pass an array to something that's expecting a string. We can do this by calling the first test function with arrays as arguments..

Code:
testVar arrDef, arrRef, arrVal

when i try to assign a string to the first two, which are passed by reference, I get a VBA error. The 3rd argument, which is by Value, happily assigns a string value - but back in the calling procedure, arrVal retains its original value - which proves that by value activity is confined to the calling stack for an array.

But all this doesn't matter - because lets see what happens in a class when we assign an array in each of the 3 different ways...

Code:
Option Explicit
Private pArrVal As Variant
Private pArrRef As Variant
Private pArrDef As Variant
Public Property Let arrVal(ByVal anArray As Variant)
 pArrVal = anArray
End Property
Public Property Let arrRef(ByRef anArray As Variant)
 pArrRef = anArray
End Property
Public Property Let arrDef(anArray As Variant)
 pArrDef = anArray
End Property
Public Property Get arrVal()
 arrVal = pArrVal
End Property
Public Property Get arrRef()
 arrRef = pArrRef
End Property
Public Property Get arrDef()
 arrDef = pArrDef
End Property


Private Function classRef()
 Dim ValRef As New cValRef
 Dim arr(1 To 2) As String
 arr(1) = "a1"
 arr(2) = "a2"

 ValRef.arrDef = arr
 ValRef.arrRef = arr
 ValRef.arrVal = arr

 Debug.Print ValRef.arrDef(2), ValRef.arrRef(2), ValRef.arrVal(2)

 arr(2) = "changed"
 Debug.Print ValRef.arrDef(2), ValRef.arrRef(2), ValRef.arrVal(2)


End Function

the result
a2 a2 a2
a2 a2 a2

So this proves that if I change the contents of an array after it's been assigned to an instance of a class - it doesn't matter whether it was assigned by value or reference in the let property, since it is a copy of the original.

If you assigned an object with property Set (as opposed to Let), then the address of the object is stored - not the contents itself. The key point here is that an array in VBA is not an object, as it is in some other languages such as JavaScript.

You'll find more about all this here - Getting Started with argument passing - Desktop Liberation





Property let only has one argument .. That's because it's used like this.

Code:
A.prop = X

X is the argument that arrives as an argument.

A Let is always by value, so if pass an array and assign to a property of a class, it will be a copy of the array. This means that if you change an array element of a class, the original array that was assigned remains unchanged.

Each instance of a class will have a copy of the array at the time it was assigned,

This is in contrast to the set property which would store the address of an object, and changes made would reflect in the original object.

Unlike some other languages, an array in vba is not an object, which is why you use let.

So
A.. By ref should be avoided in any case. A function should not update its own arguments as a general principle, and in any case, it doesn't apply with property let.
B. An array in an object can simply be updated by a.prop(1) = y



In general arguments should be passed by ref - the default. You would need to be doing something special to want to change that. So in principle - leave it alone. The main reason for byVal is so that VBA can call windows APIs and other special things in other languages that are expecting the value of a variable rather than its address on the call stack.

My comment about by ref should be avoided meant ---> updating arguments passed by ref should be avoided - a function should not be designed to create side effects like this (although some of the older built in functions in VBA, like the ones that access the IDE code itself, actually do this) - so never, ever do it.

THOUGH I'M NOT SURE ABOUT THIS STATEMENT:

Code:
The concept of multiple arguments to a let property doesn't make sense, since the syntax of using it is

Code:
a.property = theArgument

A property let will store the value of theArgument in the given property via the Property Let definition, (even if theArgument is an array).

A property set will store the address of theArgument .. which will be an object
In other words forget about byref and byvalue when dealing with property let.

If you need to provide multiple values, use a function instead

Code:
Public function DataArrayItem(RowIndex As Integer, ColIndex As Integer, Item As Variant)

pDataArray(RowIndex, ColIndex) = Item

End function
 
Last edited:
Upvote 0

Forum statistics

Threads
1,216,473
Messages
6,130,838
Members
449,597
Latest member
buikhanhsang

We've detected that you are using an adblocker.

We have a great community of people providing Excel help here, but the hosting costs are enormous. You can help keep this site running by allowing ads on MrExcel.com.
Allow Ads at MrExcel

Which adblocker are you using?

Disable AdBlock

Follow these easy steps to disable AdBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the icon in the browser’s toolbar.
2)Click on the "Pause on this site" option.
Go back

Disable AdBlock Plus

Follow these easy steps to disable AdBlock Plus

1)Click on the icon in the browser’s toolbar.
2)Click on the toggle to disable it for "mrexcel.com".
Go back

Disable uBlock Origin

Follow these easy steps to disable uBlock Origin

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back

Disable uBlock

Follow these easy steps to disable uBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back
Back
Top