B4J Question Problem when copying structure

Nandosta

Member
After copying a structure that has been defined with a user type to another structure of the same type, both structures seem to share the same memory location. Bug or feature?
(B4J version 9.3)

Source code:
'Non-UI application (console / server application)
#Region Project Attributes
    #CommandLineArgs:
    #MergeLibraries: True
#End Region

Sub Process_Globals
    Type Control_Block(P1 As String, P2 As Int)
    Private A As Control_Block
    Private B As Control_Block
End Sub

Sub AppStart (Args() As String)

    Log("Assign initial values")
    A.P1 = "A"
    A.P2 = 100
    B.P1 = "B"
    B.P2 = 200
    DMP_Control_Blocks

    Log("Copy one user type structure to the other (B = A)")
    B = A
    DMP_Control_Blocks
    
    Log("Change control block contents (A.P1 = XXX, B.P2 = 999)")
    A.P1 = "XXX"
    B.P2 = 999
    DMP_Control_Blocks
    
End Sub

Sub DMP_Control_Blocks
    Log("> A.P1 = " & A.P1)
    Log("> A.P2 = " & A.P2)
    Log("> B.P1 = " & B.P1)
    Log("> B.P2 = " & B.P2)
End Sub

Log file:
Waiting for debugger to connect...
Program started.
Assign initial values
> A.P1 = A
> A.P2 = 100
> B.P1 = B
> B.P2 = 200
Copy one user type structure to the other (B=A)
> A.P1 = A
> A.P2 = 100
> B.P1 = A
> B.P2 = 100
Change control block contents (A.P1 = XXX, B.P2 = 999)
> A.P1 = XXX
> A.P2 = 999
> B.P1 = XXX
> B.P2 = 999
Program terminated (StartMessageLoop was not called).

The value change of A.P2 and B.P1 was not expected.
 

MicroDrie

Well-Known Member
Licensed User
Longtime User
You program
Log("Copy one user type structure to the other (B = A)")
B = A
You make the definition the same and then (based on your question) you apparently want them to be different. Sounds like a contradiction. Apparently you actually want to achieve something different.
 
Upvote 0

Nandosta

Member
I used this mechanism often in VB6 to backup complete structures. The idea is to create two (or more) structures of the same type, let's call it an original one and a backup one, so that it can be copied as a whole. If the changes to the original structure need to be undone, the values of the backup structure can be used to restore them.

I know I could do this by using separate copy statements, one for each element (B.P1 = A.P1, B.P2 = A.P2) but being able to copy the whole structure with a single statement is much more elegant and easy, especially if the structure contains a geat number of items. Also, you just have to modify the type once at a sinlgle place without the need to modify the copy statements.

When writing B = A, I assumed the contents of the structure would be copied over and not that I would change the structure pointer.

So here is the result of the same code in VB6. Only A.P1 and B.P2 have changed, like I expected it to be.

Result in VB6:
Change control block contents (A.P1 = XXX, B.P2 = 999)
> A.P1 = XXX
> A.P2 = 100
> B.P1 = A
> B.P2 = 999
 
Upvote 0

agraham

Expert
Licensed User
Longtime User
When writing B = A, I assumed the contents of the structure would be copied over and not that I would change the structure pointer.
Nope. All the languages I know behave like this. C, C++, C#, Visual Basic (.NET), Java, Python etc. All implement the value of a non-primitive variable as the pointer to the object in memory. Assignment is always copying the value of the variable to another variable, this being either a primitive value or an object reference.

I've never used VB6 but I am a bit surprised it doesn't also do this.

EDIT: I'm wrong about Visual Basic (.NET). Apparently structures have value semantics, like strings, and ARE copied rather than assigned. It's many years since I used VB and don't remember - or more likely never knew - about that wrinkle which is likely a carry over from VB6.
 
Last edited:
Upvote 0

William Lancee

Well-Known Member
Licensed User
Longtime User
This issue is so important that I thought I would add a little more.

Copying non-primitive entities is non-trivial and if an element in the Type is non-primitive, it also needs special treatment.
Moreover this requirement is recursive for embedded structures (for example lists within maps within types)

I use copyXXXX subs in these cases.
(note: the B4XSerializator is a powerful alternative but does not support Arrays of Primitives)
https://www.b4x.com/android/forum/threads/storing-map-in-list.133040/post-840478

B4X:
'    Type complexType(number As Int, text As String, colors() As Int, names As List)

Private Sub Button1_Click
    Dim aa As complexType = CreateComplexType(123, "ABCDEFG", Array As Int(xui.Color_Black, xui.Color_White), Array("William", "Malcolm"))
    Dim bb As complexType = copyComplexType(aa)
    bb.names.Set(1, "John")
    Log(aa.names.Get(1) & TAB & bb.Names.Get(1))
End Sub

'Note this sub is automatically created when you hover over the Type name in the declaration - but needs to be modified for colors and names
Public Sub CreateComplexType (number As Int, text As String, colors() As Int, names As List) As complexType
    Dim t1 As complexType
    t1.Initialize
    t1.number = number
    t1.text = text
    t1.colors = copyIntArray(colors)
    t1.names = copyList(names)
    Return t1
End Sub

Public Sub copyComplexType(ct As complexType) As complexType
    Dim resultCt As complexType
    resultCt.Initialize
    resultCt.number = ct.number
    resultCt.text = ct.text
    resultCt.colors = copyIntArray(ct.colors)
    resultCt.names = copyList(ct.names)
    Return resultCt
End Sub

Public Sub copyIntArray(ar() As Int) As Int()
    Dim resultAr(ar.length) As Int
    For i = 0 To ar.Length - 1
        resultAr(i) = ar(i)
    Next
    Return resultAr      
End Sub

Public Sub copyList(aList As List) As List
    Dim resultList As List
    resultList.Initialize
    For i = 0 To aList.Size - 1
        resultList.Add(aList.Get(i)) 'if item is non-primitive then a pointer to a shared object is added
    Next
    Return resultList  
End Sub
 
Upvote 0

Nandosta

Member
Thank you all for your feedback.

I just ran a test in Excel/VBA (Visual Basic for Applications) with the same result as for VB6. The items of the structure are copied over, one by one.

I presume this is a topic that needs to be added to the list of differences / incompatibilites with VB6?
 
Upvote 0
Top