Passing array or class, ByVal or ByRef

confusion123

Active Member
Joined
Jul 27, 2014
Messages
400
This article states objects are always passed ByRef,passing arrays are always ByRef and passing classes are like passing object variable types.

Passing Variable ByRef And ByVal

This is my code in a class:

Code:
Private pDataArray As Variant

    Private pDataArrayRows As Integer
    
Property Get DataArray() As Variant

    DataArray = pDataArray

End Property

Property Let DataArray(ByVal DArray As Variant)

    pDataArray = DArray

End Property

Property Get DataArrayItem(ByVal RowIndex As Integer, _
                           ByVal ColIndex As Integer) As Variant

    DataArrayItem = pDataArray(RowIndex, ColIndex)

End Property

Property Let DataArrayItem(ByVal RowIndex As Integer, _
                           ByVal ColIndex As Integer, _
                           ByVal Item As Variant)
    
    pDataArray(RowIndex, ColIndex) = Item

End Property

Public Sub EraseArray()

    If IsArray(pDataArray) Then Erase pDataArray

End Sub

Property Get DataArrayRows() As Integer

    DataArrayRows = pDataArrayRows

End Property

Property Let DataArrayRows(ByVal DArrayRows As Integer)

    pDataArrayRows = DArrayRows

End Property

The code works perfectly but I am confused. Am I passing a class or an array or both?

Note the keywords ByVal.

If I am passing a class (or an array) then according to the article, it should be passed ByRef only.
 
Last edited:
No, they can't. Variants can, and a Variant may contain an array, but you cannot directly pass an array ByVal. Your original code doesn't pass a class or an array, it passes Variants which is why you can do it ByVal.
 
Last edited:
Upvote 0

Excel Facts

What is the shortcut key for Format Selection?
Ctrl+1 (the number one) will open the Format dialog for whatever is selected.
Hi con123
.......
So if I understand you correctly, this statement is FALSE:

Arrays are always passed ByRef so using the keyword ByVal or ByRef is the same in that case.

ie arrays CAN be passed ByRef AND ByVal?

Difficult to say that exactly, - it is a case of how you define "passing your Array"

Looking at in terms of Sub Procedures and Functions, then the codes from mikerickson Post # 14 and my Function Equivalents in post # 16 are saying this....................

Look Inside the “Procedure’s signature“, that is to say inside the Parenthesis here
Sub PassByVal(__________)
Or
Function FunkPassArrayByVal(_________)
Etc...

That is where you put in the thing you are passing.

Strictly speaking an Array is declared something like this

Dim Array() As
For example
Dim Array() As String

Here I have defined a Dynamic Array ( dynamic means I do not know its size yet ) whose Elements will be of type String.

If you really want to pass something of this form in the signature you will see form my first code that it will only work ByRef. Trying ByVal will give a syntax Error. So strictly speaking, by the “letter of the law” as Rory said, you cannot do that.

However, you probably know that a Variable assigned to Variant type can be anything. (Including an Array defined correctly with the () bit ).

What my second Code and both mikerickson’s codes demonstrate is that you can pass a Variant Variable as either ByVal or ByRef. So if you define the thing which is being passed as a Variant you can call the Sub Routine or Function and give it an Array() at the calling line in the main code. This Array() will be “housed” ( “hidden” if you like ) within the Variant. So VBA will not “see” it at first glance as An Array(). The Array() will pass through “hidden” within the Variant, and come back out after the called Sub procedure or called Function ends and returns what is in the Variant. What is in the Variant can be the modified Array() which was taken in within the Variant. ( That is what mikerickson’s called Sub Procedures and my called Fuctions do – they modify the Array() ). Think of it as if VBA did not “notice” it had an Array hidden in the Variant. So it was happy to take it ( or rather the Variant Variable ) as ByRef or ByVal

If you step through our codes in debug Mode ( F8 ) i think you will understand
Alan
 
Last edited:
Upvote 0
Hi
_ . I deeply apologise for any confusion but I have changed my Opinion. IMVHO “...you can pass an Array by Value.....”

_. I will attempt to explain. I fully expect I am wrong due to some subtle deep down thing that is going on in VBA and would be very happy for anyone to set me straight. Until then, this is my Story and i am sticking to it.

The Story.
_. Imagine an Imaginary World.
General Description of this world:

_. In this World there is a large Island called ApplicationOfEngland. Close by there is a smaller Island called The Isle of CallableProcedures.
_. There are two Ferries serving the two Islands which share the same Ports and sail in parallel routes. One is called
shigByRef
and the other
shigByVal
_. There is one main Road leading to and from the Ports. So effectively the Ferries are used to connect the two Ports. That is to say, the Ferries serve as to transport to and from the Island. There is a Control Point and a Junction at each Port Entry. The purpose of the Control Point is to Determine which Ferry will be used.
_. There is, amongst other things, an interesting special form of transport in our Imaginary World. It is something we might imagine to be a very large “Smart” Bus. - Noting there are concepts here in the imaginary World beyond our understanding,...( like in VBA )..!..., - This Bus, called Variant has the interesting characteristic that you can just about accommodate anything and do anything in it. ( You could even put ApplicationOfEngland Init ..( and maybe the entire World ! )
_...................................

_. There are various Laws ( of Nature and Government ) governing our Imaginary World.

_. Law 1. Cloning
. It is possible to clone all Things and Peoples, that is to say make a perfect copy. This can be done very quickly and a large amount of times. This cloning is generally controlled by the Port Authorities.

_. Law 2. Residence
_2a) In ApplicationOfEngland Many Things and people may exist and reside.
_2b) In Isle of CallableProcedures no residence is allowed. However Things, People and a large amount of Clones may visit for short periods of time, provided they use the Ferries to and from The Isle of CallableProcedures

_. Law 3. Port Controls and Visiting of The Isle of CallableProcedures
_3a) Anyone or Thing wishing to visit The Isle of CallableProcedures must use the Main roads and Ferries. They should also expect and accept to be controlled at least once at a Port.
_3b) It is required that anyone or Thing wishing to visit The Isle of CallableProcedures is labelled either with ByVal or ByRef. Should anyone arrive at the Port Control in ApplicationOfEngland with no label, they will be given the label ByRef at the Port in ApplicationOfEngland.
_3c) You can probably start to guess what happens at the Port Control in ApplicationOfEngland:
_3c)(i) Things and people that are labelled with ByRef are routed to the Ferry shigByRef. They are taken to The Isle of CallableProcedures. During their visit they may change themselves if they wish. They must return using the Ferry ByRef. No further control or action is taken on them by the Port Authorities and they may continue to exist in ApplicationOfEngland in their current form, on their return, be it in their original Form or in any changed Form caused by changes taking place during their visit.
_3c(ii) Things and People labelled with ByVal have a more interesting experience in their attempt at a visit to The Isle of CallableProcedures. They are stopped at the port Control in ApplicationOfEngland. They are prohibited from visiting The Isle of CallableProcedures. However, they are cloned. Their clone is routed to the Ferry shigByVal. The clones are allowed all the same experiences as privileges in The Isle of CallableProcedures as their “real” counterparts would have had should they have come to The Port in Application of England with a ByRef Label. However on Return to the Port Control, ( or shortly after ) in The Isle of CallableProcedures, something unexplained happen. Exactly what happens next is not known. They are routed as may be expected to the Ferry shigByVal. Theories of what then happens include that on the return trip on the Ferry shigByVal they are thrown overboard, killed, or in some way they vanish without trace.

_................................

Back to my original “....you can pass an Array by Value....”
Consider this parallel.
The Port Authorities claim that groups of people, such as a School Class ( Class of School Children Group ) are prohibited from using the Ferry shigByVal. ( Or in other words, their clones will either not be made or if made not allowed on the Ferry shigByVal . - All amounting in effect to the same thing. )
However A Variant Bus containing such a group and labelled ByVal will be permitted to visit The Isle of CallableProcedures in the usually way via The “Clone “ route with Ferry shigByVal. ( or rather the clone thereof including the Group will be permitted to sail. in Ferry shigByVal..)

Possible the following explanation, and the parallel in VBA, is the “trick” that allows effectively this contradicting Visit type.
Somehow it is possible for The group to be effected, changed, etc., whilst in the Bus Variant as if they were free to “roam” in The Isle of CallableProcedures.
To consider my parallel to VBA take a look at my Sub Test4() in post #16 and both Sub test1() and Sub test2() from mikerickson in post # 14. In particular consider the first two code lines in the Procedure called by those Test Subs(). Somehow I can use the Variant using things in brackets such as i would do If I had an Actual Array(). And in doing so I change The Array() ( as demonstrated in the examples by changing the number of elements and one Element value ) as it would be changed in the Array() case. But it still is “within” the Variant. Think of that as being like the Group in the Bus Variant being able to interact with things in The Isle of CallableProcedures as if they were free to roam normally in The Isle of CallableProcedures. This is possible despite the Bus being closed, or at least closed to the extent that the Port Authorities could not, or did not choose to envisage, that a group of people had sailed / were sailing in the Ferry shibByVal. ( Of course they were / did. ... i think...)

_....
So A group of School Children ( or rather a clone thereof) visited The Isle of CallableProcedures using the Ferry shigByVal.
An Array() ( or rather Copy thereof ) may be passed to a procedure ByVal


Alan
 
Last edited:
Upvote 0
ie arrays CAN be passed ByRef AND ByVal?

I think, strictly it is true that you cannot pass an Array ByVal. That is if you mean something like:
Code:
Sub mySub(ByVal arr() As String)
However, you can pass Variants ByVal and ByRef. So if you use a Variant as an Array then yes, you can use both.

It would be no fun if Excel was completely straightforward, would it? :)
 
Upvote 0
An Array() ( or rather Copy thereof ) may be passed to a procedure ByVal [/B]

No. A Variant may be passed ByVal, and it may happen to contain an array, but that is not the same thing as passing an array ByVal, which is explicitly prohibited by the compiler.

This workaround is not really a workaround. It is a removal of the entire issue and can only be performed by altering the called routine's declaration.
 
Upvote 0
It still sounds to me a case of how you look at it.
Can I post a collection of Letters? I can Post a stamped Envelope which contains a collection of letters. The Address says where the Letters can be read. If I post the letters ( By Putting a CopVay of them or the ORefiginals in the Post box ) the collector should prohibit it. The analogy is not perfect. I cannot write or change my letters easily while they are in the Envelope. The subtle difference in the VBA analogy was the “trick” i suggested that was responsible for the thing to ”work”

I do not alter the called routine's declaration. I make it that way from the outset. I did not change the Post Office to deal with letters in an Envelope. It always did and was designed that way to take my letters. The test codes Post # 14 ( I use mikerickson’s not mine as example here as one of mine is truly taking an array ( ByRef ) ) were written so as to take an Array ( by taking an actRual one or a copVy thereof ) inside a Variant.

If anyone asks me I shall say that I can post a letter and that I can pass a copVy ( the ByVal case ) of an Array in VBA

But I will tell them I think I am wrong, as Rory told me so.
It will not do any harm. No one speaks English here in Hof, Bavaria . So in the very unlikely event they should ask, they would not understand my answer anyway....
Alan
 
Upvote 0
I do not alter the called routine's declaration. I make it that way from the outset.

Again, that assumes that you are the author of the routine in question. In any event, if you have a routine that should take an array as argument, and you think you need to pass it by ByVal, you may as well simply copy the array to a new array and pass that one ByRef. It achieves the same thing without needing an additional variant.
 
Upvote 0
You can also use a local array in your routine. This simulates passing the array ByVal.

Notice that copying the parameter array to a local array is a simple direct assignment.
 
Last edited:
Upvote 0
Hi Rory and pgc...
.... if you have a routine that should take an array as argument, and you think you need to pass it by ByVal, you may as well simply copy the array to a new array and pass that one ByRef. It achieves the same thing without needing an additional variant.
........Notice that copying the parameter array to a local array is a simple direct assignment.
_ ..........Nice straight forward idea i suppose.
_. Again in simple terms, what you are saying:
_ . Do not send the actual Array I originally wanted to send ByCopVy. ( that is to Say putting it in as ByVal in the Called Procedure shignature ) .

Instead,
_ . i) CopVy it ( in the mainn program ) ( that is to say declare a __Temp orary() __ Array and do the simple VBA allowable direct assignment to the actual Array I that originally wanted to send ByCopValy. )

_. ii) Send that CopValy by putting that Array Temp() in the calling Line ..

Call FunkPassArrayByRef( Temp() )

( The procedure FunkPassArrayByRef( ByRef AnArray() As _______ ) which I am using is of the form of what we know is the only allowed VBA direct way to take an Array into a called Procedure )

_ . I guess it could be described as a simple ““By Proxy” Call ByCopVy “ or “By Proxy Call ByVal”. -I say this because My original Array has nothing to do with the Called procedure. So Any trace back, virus, or anything effecting the given Array ( which is the Temp() Array ) will hopefully stay contained within the Temp() Array, which i probably do not want to keep. ( So just as good practice may be worth “emptying.....” it, just to stop any nasties that might leak out !)! )

_...........................

At the end of the day, I have a very vague abstract understanding of it all now.... Back to my original vague explanation..and enlightened a bit by these two Threads:
http://www.mrexcel.com/forum/excel-questions/917689-passing-array-class-byval-byref.html
http://www.mrexcel.com/forum/excel-questions/361246-vbnullstring.html ........

“.....There is a very complex way of what happens when a code line hits a Variable with an Array in it... that is to say the Pointing to a Pigeon Hole , with an Address ( often just the initial, start, provisional ) of where the Filled element may or may not be and then that address may change along the way if and when other used addresses get freed up. Etc.. etc... “
This all causes a very complex “ offset referencing structure .." ( further complicated again in the particular case of String Elements .. they are even more likely to change there addresses of where things are along the way ). This suggests a volatility of horrendous complexity which the software will struggle to keep up with. This is a bit less complex or volatile if we take the ORefiginal Array rather than a copVy of it.. So maybe that explains why VBA only allows directly an a ByRef Call.

_........

As for the “hiding a ( CopVy of ) Array() ( ByVal ) inside a Variant” and sending that....
_ .... Well maybe a Variant can be so versatile ( even can be an Object ) that it has a great chunk of the Application.Excel in it and maybe even has a “pseudo” ByORefviginal Array what helps it to keep track of any ( CopVy of ) Array() ( ByVal ) init enit? .. maybe. So maybe then that is all a bit memory / speed intensive. I guess the “Poxy ByCopVy ByORefiginal” way is then a less “indirectindirect” way to do “it”. Maybe one is doing what goes on in the Variant but a bit more efficiently with the “Proxy” way..

Thanks very much guys.
Alan


_ .................
P.s.
Maybe could put a Pole up in the Lounge Sub Forum..

Titel:
Q. Can you pass an ( CopVy of ) Array() ( ByVal ) to a Procedure ( in the Procedure’s shignature ).
I will not say Yes, because i am sure you can, - so that probably means you can’t ;) )

P.P.s.
Just another few codes to bring out the last few points. Mainly the “Poxy ByCopVy ByORefiginal” way

_ - ( I do a string Array Element Type of my test3() code first, ( here test5() ) as it seems to work, and for some reason I did not think it did, but it does, ( confirming again that if i think you can pass an ( CopVy of ) Array() ( ByVal ) to a Procedure ( in the Procedure’s shignature ), then you probably can’t ;) )
_ - the Strings is good one to choose I guess, - the particularly horrendous complexity in handling those Pointed Pigeion Hole Addresses being the cause of much of the trouble.. )

_ - So... then.... test6() is the calling main Procedure to demo the "Poxy ByCopVy ByORefviginal" idea.
_ . But it calls the same ByORefiginal Funktion as test5().
That is a basic Direkt Array() ByRefiginal CallableProcedures ( Funktion ) Piddlyfiddlypoo I thought this was a good idea so as not to cause a “...... removal of the entire issue …. only being performed by altering the called routine....“ situation of exceptional naughtiness.... LOL.. ;)

_. The Proxy Call to a ( ByRef Procedure ) is done by a temporary array, myTempArrayCopVyForFunkByORefiginal(), which in the main program is copied from my original Array, myArray().
The temporay Array "goes" to, and comes back from ( in a modified state ), the Called procedure ( Function )
A simple test is done on return, as in the other test codes. This shows the state of the returned from function Array and the state of the original Array. As expected the original Array is unchanged. This time it is because we did nothing to that ( We read it by copying it but did not do anything to it ( I think ? ) as we did not do any writing tu-it ).
( Finally, just as good practice the Temporary Array is “emptied” !)! )


Code:

Code:
[color=darkgreen]'[/color]
[color=blue]Sub[/color] test5() 'Pass an Array to a Funktion ByRef String Array Element version
[color=blue]Dim[/color] myArray() [color=blue]As[/color] [color=blue]String[/color] [color=darkgreen]'[/color]
[color=blue]ReDim[/color] myArray(1 [color=blue]To[/color] 3)
myArray(1) = " one": myArray(2) = "two": myArray(3) = "three"
 
[color=blue]Dim[/color] myArray2() [color=blue]As[/color] [color=blue]String[/color]
[color=blue]Let[/color] myArray2() = FunkPassArrayByRefRStrp(myArray())
 
MsgBox [color=blue]UBound[/color](myArray) & myArray(1) [color=darkgreen]' "2 first" ' Changed because myArray() Taken  ( ByRef )[/color]
MsgBox [color=blue]UBound[/color](myArray2) & myArray2(1) [color=darkgreen]' "2 first" ' Result returned from Function[/color]
[color=blue]End[/color] [color=blue]Sub[/color]
[color=darkgreen]'[/color]
[color=blue]Function[/color] FunkPassArrayByRefRStrp(ByRef anArray() [color=blue]As[/color] [color=blue]String[/color]) [color=blue]As[/color] [color=blue]Variant[/color] ''( String Array version )
[color=blue]ReDim[/color] [color=blue]Preserve[/color] anArray(1 [color=blue]To[/color] 2)
anArray(1) = " first"
[color=blue]Let[/color] FunkPassArrayByRefRStrp = anArray()
[color=blue]End[/color] [color=blue]Function[/color]
[color=darkgreen]'[/color]
'   "Poxy ByCopVy ByORefiginal"     ---o00o---`(_)`---o00o---
[color=blue]Sub[/color] test6() [color=darkgreen]'Pass an Array to a Funktion ByVal using copy to ByRef Funktion ( String Array Element version )[/color]
[color=darkgreen]'..... The Array  myArrayTempCopVyForFunkByORefiginal()  will be myPoxyByCopVyByORefiginal()  Array[/color]
10  [color=blue]Dim[/color] myArray() [color=blue]As[/color] [color=blue]String[/color] [color=darkgreen]'Maybe a point ..er ... thing  somewhere ..probably temporary addresses in a Pigeion hole pointed to when code sees myArray, or maybe no address in there yet, that is to say address 0[/color]
20  [color=blue]ReDim[/color] myArray(1 [color=blue]To[/color] 3) [color=darkgreen]'3 Element "Pseudo" 1 D Array with vbNullString Elements.. probably a whole lot of new addreses in the[/color]
30  [color=blue]Let[/color] myArray(1) = " one": [color=blue]Let[/color] myArray(2) = "two": [color=blue]Let[/color] myArray(3) = "three" [color=darkgreen]'Element filled, and very likely a chaos already with changing addresses in the pegion hole, especillay due to using Strings where the start may no longer be appropriate to cope with the extending differe3nt lengths....[/color]
40
50  [color=darkgreen]'Rory pgc  copying the parameter array to a local array is a simple direct assignment.      to pass it by ByVal, you may as well simply copy the array to a new array and pass that one ByRef       http://www.mrexcel.com/forum/excel-questions/917689-passing-array-class-byval-byref.html#post4415394[/color]
60  [color=blue]Dim[/color] myTempArrayCopVyForFunkByORefiginal() [color=blue]As[/color] [color=blue]String[/color] [color=darkgreen]'probably temporary addresses in a Pigeion hole pointed to when code sees myArrayCopVyForFunkByORefiginal[/color]
70  [color=blue]Let[/color] myTempArrayCopVyForFunkByORefiginal() = myArray() [color=darkgreen]'Direct assignment works. ( Here a Static Array assigned to a Dynamic. Works as Element Types are the same ). Becomes identical Array ( well sort of.. obviously the Pointer, and addresse therein will be different[/color]
80  [color=blue]ReDim[/color] myTempArrayCopVyForFunkByORefiginal(1 [color=blue]To[/color] 3) [color=darkgreen]'Resets it back to a 3 Element "Pseudo" 1 D Array with vbNullString Elements[/color]
90  [color=blue]Let[/color] myTempArrayCopVyForFunkByORefiginal() = myArray() [color=darkgreen]'Just to demo can assin a Static Array to a Static Array if they are the same size and Type[/color]
100
110 [color=darkgreen]'Send off the "Poxy ByCopVy" By a oRefiginal[/color]
120 [color=blue]Dim[/color] myArray2() [color=blue]As[/color] [color=blue]String[/color] [color=darkgreen]'Compatible variable to take returned value from Called procedure ( Function )[/color]
130 [color=blue]Let[/color] myArray2() = FunkPassArrayByRefRStrp(myTempArrayCopVyForFunkByORefiginal())
140 MsgBox [color=blue]UBound[/color](myArray) & myArray(1) [color=darkgreen]' "3 one" ' Not Changed - never sent it ByRef ( or anything at all ! )[/color]
150 MsgBox [color=blue]UBound[/color](myArray2) & myArray2(1) [color=darkgreen]' "2 first" ' Result returned from Function[/color]
160
170 Erase myTempArrayCopVyForFunkByORefiginal() [color=darkgreen]'release array variables and deallocate the memory used for their elements. Goes back to probably temporary addresses in a Pigeion hole pointed to when code sees myArrayCopVyForFunkByORefiginal[/color]
180
190 [color=darkgreen]' Other stuff requiring myArray() but not requiring myTempArrayCopVyForFunkByORefiginal()[/color]
[color=blue]End[/color] [color=blue]Sub[/color]


A file with all the codes in, ( somewhere! )
https://app.box.com/s/lalxqrzrzjexpb0vmgufxf085elbuern
 
Upvote 0

Forum statistics

Threads
1,213,560
Messages
6,114,309
Members
448,564
Latest member
ED38

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