OpenOffice BASIC: Create an independent copy of an array.
Posted: Thu May 17, 2018 10:07 pm
===Editing again 2021-12-30===
Due to a recent request I want to explicitly state that arrays being elements of an array copied the way described here should be expected to be result of an internal assignment by reference, as is standard for arrays.
In different words: The deep copy will not propagate to the elements of nested arrays.
===End Edit 2021-12-30===
Editing:
I have to apologize for insufficient verification of the code. It did not work correctly in an example "JeJe" provided.
I will replace it now with a slightly reworked version working correctly for me in LibO V6.0.3 and also in AOO V4.1.5.
Be careful, please. I cannot give any guarantee. Errors still expected!
In addition I attach a .ods file containing the test by JeJe, the reworked code, and an enhanced version for arrays up to 5 dimensions. Start of the original text:[/i]
Arrays (and structures) are generally assigned to variables by reference in OpenOffice BASIC (and beyond). Hence I am only talking about arrays. I will recap in short what "by reference" means.
If the variable A is declared by A(0 To 3, 1 To 2) e.g. and you make an assignmen B = A then accessing B does exactly the same as accessing A. A(1,2) = 3 will force B(1,2) to also have the value 3. A subsequent B(1,2) = "Z" will cause A(1,2) to return "Z".
This is often the desired behaviour. Think alone of storage efficiency. It involves, however, that an array passed to a routine (Sub, Function) via a parameter specified with the ByVal clause also only can get the reference where it is not of high importance if this reference is primarily one to the varibale you access the array with or directly to the array.
On the other hand there are cases where you want to create a new array B and to only inititialize it with the contents of A while both the names actually shall give access to two arrays whose elements can be changed independently afterwards.
Since I today considered this anew and got an idea how to avoid the need of copying elments one by one explicitly in a way I not yet had seen, I want to present the solution to you and to request for your comments and criticisms. See code below.
This is specialized to arrays of exactly 2 dimensions. To do it for only one or for more dimensions (up to a reasonable limit) is also feasible.
Due to a recent request I want to explicitly state that arrays being elements of an array copied the way described here should be expected to be result of an internal assignment by reference, as is standard for arrays.
In different words: The deep copy will not propagate to the elements of nested arrays.
===End Edit 2021-12-30===
Editing:
I have to apologize for insufficient verification of the code. It did not work correctly in an example "JeJe" provided.
I will replace it now with a slightly reworked version working correctly for me in LibO V6.0.3 and also in AOO V4.1.5.
Be careful, please. I cannot give any guarantee. Errors still expected!
In addition I attach a .ods file containing the test by JeJe, the reworked code, and an enhanced version for arrays up to 5 dimensions. Start of the original text:[/i]
Arrays (and structures) are generally assigned to variables by reference in OpenOffice BASIC (and beyond). Hence I am only talking about arrays. I will recap in short what "by reference" means.
If the variable A is declared by A(0 To 3, 1 To 2) e.g. and you make an assignmen B = A then accessing B does exactly the same as accessing A. A(1,2) = 3 will force B(1,2) to also have the value 3. A subsequent B(1,2) = "Z" will cause A(1,2) to return "Z".
This is often the desired behaviour. Think alone of storage efficiency. It involves, however, that an array passed to a routine (Sub, Function) via a parameter specified with the ByVal clause also only can get the reference where it is not of high importance if this reference is primarily one to the varibale you access the array with or directly to the array.
On the other hand there are cases where you want to create a new array B and to only inititialize it with the contents of A while both the names actually shall give access to two arrays whose elements can be changed independently afterwards.
Since I today considered this anew and got an idea how to avoid the need of copying elments one by one explicitly in a way I not yet had seen, I want to present the solution to you and to request for your comments and criticisms. See code below.
Code: Select all
Function createArrayCopy2D(p2D)
REM Returns a reference to a newly created copy of the passed array.
REM BE CAREFUL! This is not based on profound knowledge of any specifications
REM for LibreOffice BASIC, not to speak of any knowledge of its interpreter's code.
REM This is based on speculative testing. New testers please report contradictory results.
If NOT IsArray(p2D) Then Exit Function
If NOT (dimensionality(p2D)=2) Then Exit Function
dummy = p2D
l = Array(Lbound(dummy,1), Lbound(dummy,2)
u = Array(Ubound(dummy,1), Ubound(dummy,2)
Redim Preserve dummy(l(0) To u(0), l(1) To u(1))
REM The Redim command does not test if any dimnsion is actually changed.
REM By way of precaution it creates a copy with ReferenceCounter=1
REM and decrements the ReferenceCounter of the source by 1.
REM This way the calling position will get returned a reference to the copy
REM while the source array wherever referenced in advance will be unchanged.
createArrayCopy2D = dummy
End Function
Function dimensionality(pArray)
REM Returns the dimensionality of an array.
dim d As Long ' The code relies on the initialization with 0.
If NOT IsArray(pArray) Then Exit Function
On Local Error Goto doneExit
REM Below the Ubound() function is only used to raise an error when needed.
REM Its result, if returned, gets annulled.
Do
d = Ubound(pArray, d+1)*0 + d + 1
Loop
doneExit:
dimensionality = d
End Function