Page 1 of 1

OpenOffice BASIC: Create an independent copy of an array.

Posted: Thu May 17, 2018 10:07 pm
by Lupp
===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.
arrayCopyByVal_1.ods
(11.81 KiB) Downloaded 478 times
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 
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.

Re: OpenOffice BASIC: Create an independent copy of an array

Posted: Thu May 17, 2018 11:07 pm
by JeJe
Doesn't work here - try this test code.

Code: Select all


sub tmp

dim aa(0 to 50,0 to 40)

aa(10,10) =80
dim bb(0 to 50,0 to 40)
bb = createArrayCopy2D(aa)
aa(10,10) =50
msgbox bb(10,10) 'result is 50 not 80
end sub



Re: OpenOffice BASIC: Create an independent copy of an array

Posted: Thu May 17, 2018 11:52 pm
by JeJe
On Windows the CopyMemory Api function is a way of copying all the values in one array to another... but testing that, it works for a single item of an array but not the whole array. So - presumably OO array items aren't stored in contiguous memory locations.

I notice if you make an assignment array2 = array1 and then Erase array1 then array2 isn't erased. OO array variables appear to be pointers to an array and its maybe not possible to do what you want to do here. OO is alway going to be copying the pointer to the array... never making a new array.

Re: OpenOffice BASIC: Create an independent copy of an array

Posted: Fri May 18, 2018 12:22 am
by Lupp
Hallo JeJe,

Thank yopu very much for testing - and bashful apologies for my prematurely pasting insufficiently verified code.

I do not fully understand the problem. When I wrote and tested the functions (And it worked!) there were a few more assignment of the relevant array to different variables, among them a few indexed variables (array elements). Probably this has influenced parts of the environment.

Since i don't know a documentation on which I might base further development, I could only try a solution based on guessing again. Now there is an intermediary variable inside the relevant function serving to give access to the original array over a bridge that is burnt finally when the function is left.

And now your test suggests correct working - for the example.
I would not yet rely on the method with crucial tasks.

Please see the reworked code contained in the .ods I will attach now to my first post.

Apologies again!

Re: OpenOffice BASIC: Create an independent copy of an array

Posted: Fri May 18, 2018 12:57 am
by JeJe
That works... redim preserve creates a new copy of the array - well spotted. This seems to work too...

Code: Select all


dim aa(0 to 50,0 to 40), bb(0 to 50,0 to 40)
aa(10,10) =80
bb = aa 
redim preserve bb(0 to 50,0 to 40) 'or redim preserve aa 
aa(10,10) =50
msgbox aa(10,10)
msgbox bb(10,10)

Re: OpenOffice BASIC: Create an independent copy of an array

Posted: Fri Jul 10, 2020 5:47 pm
by Lupp
JeJe wrote:That works... redim preserve creates a new copy of the array - well spotted. This seems to work too...

Code: Select all

dim aa(0 to 50,0 to 40), bb(0 to 50,0 to 40)
aa(10,10) =80
bb = aa 
redim preserve bb(0 to 50,0 to 40) 'or redim preserve aa 
aa(10,10) =50
msgbox aa(10,10)
msgbox bb(10,10)
Yes. I think I chose the function approach to get a containment for calls to helper functions (from my little framework of array-related routines). Since these functions were not included here, and aren't actually in a shape to do it, the createArrayCopys?? functions may look a bit hollow. But generally a function createArrayCopy should be able to work on all kinds of Basic arrays (any dimnsionality or, say, up to 5 dimesions) and probably even on API-arrays like the .DataArray of a SheetCellRange.

Everything would be a lot simpler if an existing variable (b) having assigned a pre-existing different array variable the ByRef way was detached from the group of variables referencing the same data-container by a simple Redim Preseve b without a need to explicitly give the index ranges.
I tried this and that in a few cases in Libreoffice, but the behavior was inconsistent.
See also:
https://bugs.documentfoundation.org/sho ... ?id=134712 and
https://bugs.documentfoundation.org/sho ... ?id=134692

Re: OpenOffice BASIC: Create an independent copy of an array

Posted: Thu Jul 16, 2020 4:49 am
by MrProgrammer
More examples and pitfalls of copying an array are in Pitonyak's Miscellaneous Topics In Macro Programming

Re: OpenOffice BASIC: Create an independent copy of an array

Posted: Thu Jul 16, 2020 1:35 pm
by Lupp
Clearance regarding my previous post.

The relevant new one of the linked bugs (tdf#134692) afflicting the routine I posted in this snippets-thread only lived in a few prereleases of LibO V7.0. It is fixed and the fix verified to my satisfaction. The bug will not afflict any release version of LibO.

The other bug I reported is also treated as RESOLVED with type WONTFIX. You may read the short discussion there if interested. (A highly efficient deep copy for arrays without a Redim Preserve as is and thus without the need to know exactly the dimensionality and dimensions does therefore still not exist.)