Variable-length member data
Management of variable-length strings/arrays as members of a Type.
Preamble:
In FreeBASIC, Type data structures must ultimately be fixed-size, such that the compiler knows how much memory to allocate for objects of that Type.
Nevertheless, Types may contain variable-length string or array data members.
However, the string's/array's data will not be embedded in the Type directly. Instead, the Type will only contain a string/array descriptor structure, which FreeBASIC uses behind the scenes to manage the variable-length string/array data.
For sizing the structure of the array descriptor in the Type, a variable-length array data member must be always declared by using Any(S) in place of the array bounds, in order to fix the amount of dimensions based on the number of Anys specified. A variable-length array data member can also be pre-sized in its declaration by using syntax with `ReDim`.
Variable-length array fields are considered as pseudo-objects when they are declared in a Type (variable-length strings are real objects).
So the implicit copy constructor and the implicit let operator of the Type themselves support [re]sizing and copying such strings/arrays, or their erasing.
Implicit string/array sizing and copying by the compiler code
When the compiler build a default copy-constructor and a default copy-assignment operator for such a Type (having string/array members), it also includes all code for sizing the destination string/array and copying the data from the source string/array, if needed.
Example:
`
Type UDT
Dim As String s
Dim As Integer array(Any)
End Type
Dim As UDT u1, u2
u1.s = "FreeBASIC"
ReDim u1.array(1 To 9)
For I As Integer = LBound(u1.array) To UBound(u1.array)
u1.array(I) = I
Next I
u2 = u1
Print u2.s
For I As Integer = LBound(u2.array) To UBound(u2.array)
Print u2.array(I);
Next I
Print
Print
Dim As UDT u3 = u1
Print u3.s
For I As Integer = LBound(u3.array) To UBound(u3.array)
Print u3.array(I);
Next I
Print
Sleep
`
Output:

    FreeBASIC
     1 2 3 4 5 6 7 8 9

    FreeBASIC
     1 2 3 4 5 6 7 8 9

Implicit string/array sizing and copying by the compiler code broken by an explicit copy-constructor and copy-assignment operator
If the user want to specify his own copy-constructor and copy-assignment operator (to initialize additional complex field members for example), the above automatic string/array sizing and copying by compiler code is broken.
Example:
`
Type UDT
Dim As String s
Dim As Integer array(Any)
Declare Constructor ()
Declare Constructor (ByRef u As UDT)
Declare Operator Let (ByRef u As UDT)
'user fields
End Type
Constructor UDT ()
'code for user fields in constructor
End Constructor
Constructor UDT (ByRef u As UDT)
'code for user fields in copy-constructor
End Constructor
Operator UDT.Let (ByRef u As UDT)
'code for user fields in copy-assignement operator
End Operator
Dim As UDT u1, u2
u1.s = "FreeBASIC"
ReDim u1.array(1 To 9)
For I As Integer = LBound(u1.array) To UBound(u1.array)
u1.array(I) = I
Next I
u2 = u1
Print u2.s
For I As Integer = LBound(u2.array) To UBound(u2.array)
Print u2.array(I);
Next I
Print
Print
Dim As UDT u3 = u1
Print u3.s
For I As Integer = LBound(u3.array) To UBound(u3.array)
Print u3.array(I);
Next I
Print
Sleep
`
Output (blank):

String/Array sizing and copying explicitly set in the user copy-constructor and copy-assignment operator
The variable-length array cannot be processed as a true object like a variable-length string, because for example there is no implicit assignment.
Referring to the above example, `This.array() = u.array()` is disallowed, while `This.s = u.s` is allowed.
The user must code explicitly the sizing and the copying of the array member (for the array data copy, a C run-time function `memcpy()` is used to optimize the execution time).
Example:
`
#include "crt/string.bi" '' C run-time header for 'memcpy()'
Type UDT
Dim As String s
Dim As Integer array(Any)
Declare Constructor ()
Declare Constructor (ByRef u As UDT)
Declare Operator Let (ByRef u As UDT)
'user fields
End Type
Constructor UDT ()
'code for user fields in constructor
End Constructor
Constructor UDT (ByRef u As UDT)
This.s = u.s
If UBound(u.array) >= LBound(u.array) Then '' explicit array sizing and copying
ReDim This.array(LBound(u.array) To UBound(u.array))
memcpy(@This.array(LBound(This.array)), @u.array(LBound(u.array)), (UBound(u.array) - LBound(u.array) + 1) * SizeOf(@u.array(LBound(u.array))))
End If
'code for user fields in copy-constructor
End Constructor
Operator UDT.Let (ByRef u As UDT)
If @This <> @u Then '' not self-assignment
This.s = u.s
If UBound(u.array) >= LBound(u.array) Then '' explicit array sizing and copying
ReDim This.array(LBound(u.array) To UBound(u.array))
memcpy(@This.array(LBound(This.array)), @u.array(LBound(u.array)), (UBound(u.array) - LBound(u.array) + 1) * SizeOf(@u.array(LBound(u.array))))
End If
'code for user fields in copy-assignement operator
End If
End Operator
Dim As UDT u1, u2
u1.s = "FreeBASIC"
ReDim u1.array(1 To 9)
For I As Integer = LBound(u1.array) To UBound(u1.array)
u1.array(I) = I
Next I
u2 = u1
Print u2.s
For I As Integer = LBound(u2.array) To UBound(u2.array)
Print u2.array(I);
Next I
Print
Print
Dim As UDT u3 = u1
Print u3.s
For I As Integer = LBound(u3.array) To UBound(u3.array)
Print u3.array(I);
Next I
Print
Sleep
`
Output:

    FreeBASIC
     1 2 3 4 5 6 7 8 9

    FreeBASIC
     1 2 3 4 5 6 7 8 9

Using an extra base Type containing the variable-length string and array
Another elegant possibility is to keep this sizing/copying, automatically coded by the compiler, but by simply calling it explicitly.
For this, an elegant solution for the member array is to no longer put it at the level of the Type itself, but rather in another specific Type which is inherited (seen from the outside, it is exactly the same). This is not necessary for the member string, but including also allows to save one code line each time.
Example:
`
Type UDT0
Dim As String s
Dim As Integer array(Any)
End Type
Type UDT Extends UDT0
Declare Constructor ()
Declare Constructor (ByRef u As UDT)
Declare Operator Let (ByRef u As UDT)
'user fields
End Type
Constructor UDT ()
'code for user fields in constructor
End Constructor
Constructor UDT (ByRef u As UDT)
Base(u) '' inherited string copying plus array sizing and copying from Base implicit copy-constructor call
'code for user fields in copy-constructor
End Constructor
Operator UDT.Let (ByRef u As UDT)
Cast(UDT0, This) = u '' inherited string copying plus array sizing and copying from Base implicit copy-assignement operator call
'code for user fields in copy-assignement operator
End Operator
Dim As UDT u1, u2
u1.s = "FreeBASIC"
ReDim u1.array(1 To 9)
For I As Integer = LBound(u1.array) To UBound(u1.array)
u1.array(I) = I
Next I
u2 = u1
Print u2.s
For I As Integer = LBound(u2.array) To UBound(u2.array)
Print u2.array(I);
Next I
Print
Print
Dim As UDT u3 = u1
Print u3.s
For I As Integer = LBound(u3.array) To UBound(u3.array)
Print u3.array(I);
Next I
Print
Sleep
`
Output:

    FreeBASIC
     1 2 3 4 5 6 7 8 9

    FreeBASIC
     1 2 3 4 5 6 7 8 9

See also

- Constructors, '=' Assignment-Operators, and Destructors (advanced, part #1)
- Constructors, '=' Assignment-Operators, and Destructors (advanced, part #2)