Nesting TYPE (temporary) keyword does not support multi-level inheritance structure

General FreeBASIC programming questions.
fxm
Moderator
Posts: 11420
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Nesting TYPE (temporary) keyword does not support multi-level inheritance structure

Post by fxm »

Nesting TYPE (temporary) keyword does not support multi-level inheritance structure (UDT1 <- UDT2 <- UDT3 ...), but only single inheritance structure (UDT1 <- UDT2).
Same behavior by replacing a nested TYPE (temporary) by an equivalent permanent variable when possible.

Example for a three-level inheritance structure (UDT1 <- UDT2 <- UDT3 <- UDT4):

Code: Select all

Type UDT1
    Dim As Integer I11, I12
End Type

Type UDT2 Extends UDT1
    Dim As Integer I21, I22, I23, I24
End Type

Type UDT3 Extends UDT2
    Dim As Integer I31, I32, I33
End Type

Type UDT4 Extends UDT3
    Dim As Integer I41
End Type

Dim As UDT1 u1
Print "No Inheritance (UDT1)"

u1 = Type<UDT1>(1, 2)
Print "  u1 = Type<UDT1>(1, 2)  => OK"
Print "    UDT1: "; u1.I11; u1.I12

Print
Dim As UDT2 u20, u2
Print "Single Inheritance (UDT1 <- UDT2):"

u2 = u20
u2 = Type<UDT2>(1, 2, 3, 4, 5, 6)
print "  Type<UDT2>(1, 2, 3, 4, 5, 6)  => OK"
Print "    UDT1: "; u2.I11; u2.I12
Print "    UDT2: "; u2.I21; u2.I22; u2.I23; u2.I24

u2 = u20
u2 = Type<UDT2>(Type<UDT1>(1, 2), 3, 4, 5, 6)
Print "  Type<UDT2>(Type<UDT1>(1, 2), 3, 4, 5, 6)  => OK"
Print "    UDT1: "; u2.I11; u2.I12
Print "    UDT2: "; u2.I21; u2.I22; u2.I23; u2.I24

u2 = u20
u2 = Type<UDT2>(u1, 3, 4, 5, 6)
Print "  Type<UDT2>(u1, 3, 4, 5, 6)  => OK"
Print "    UDT1: "; u2.I11; u2.I12
Print "    UDT2: "; u2.I21; u2.I22; u2.I23; u2.I24

u2 = Type<UDT2>(1, 2, 3, 4, 5, 6)

Print
Dim As UDT3 u30, u3
Print "Two-Level Inheritance (UDT1 <- UDT2 <- UDT3):"

u3 = u30
u3 = Type<UDT3>(1, 2, 3, 4, 5, 6, 7, 8, 9)
Print "  Type<UDT3>(1, 2, 3, 4, 5, 6, 7, 8, 9)  => OK"
Print "    UDT1: "; u3.I11; u3.I12
Print "    UDT2: "; u3.I21; u3.I22; u3.I23; u3.I24
Print "    UDT3: "; u3.I31; u3.I32; u3.I33

u3 = u30
u3 = Type<UDT3>(Type<UDT2>(1, 2, 3, 4, 5, 6), 7, 8, 9)
Print "  Type<UDT3>(Type<UDT2>(1, 2, 3, 4, 5, 6), 7, 8, 9)  => NOK"
Print "    UDT1: "; u3.I11; u3.I12
Print "    UDT2: "; u3.I21; u3.I22; u3.I23; u3.I24
Print "    UDT3: "; u3.I31; u3.I32; u3.I33

u3 = u30
u3 = Type<UDT3>(Type<UDT2>(Type<UDT1>(1, 2), 3, 4, 5, 6), 7, 8, 9)
Print "  Type<UDT3>(Type<UDT2>(Type<UDT1>(1, 2), 3, 4, 5, 6), 7, 8, 9)  => NOK"
Print "    UDT1: "; u3.I11; u3.I12
Print "    UDT2: "; u3.I21; u3.I22; u3.I23; u3.I24
Print "    UDT3: "; u3.I31; u3.I32; u3.I33

u3 = u30
u3 = Type<UDT3>(u2, 7, 8, 9)
Print "  Type<UDT3>(u2, 7, 8, 9)  => NOK"
Print "    UDT1: "; u3.I11; u3.I12
Print "    UDT2: "; u3.I21; u3.I22; u3.I23; u3.I24
Print "    UDT3: "; u3.I31; u3.I32; u3.I33

u3 = u30
u3 = Type<UDT3>(Type<UDT2>(u1, 3, 4, 5, 6), 7, 8, 9)
Print "  Type<UDT3>(Type<UDT2>(u1, 3, 4, 5, 6), 7, 8, 9)  => NOK"
Print "    UDT1: "; u3.I11; u3.I12
Print "    UDT2: "; u3.I21; u3.I22; u3.I23; u3.I24
Print "    UDT3: "; u3.I31; u3.I32; u3.I33

u3 = Type<UDT3>(1, 2, 3, 4, 5, 6, 7, 8, 9)

Print
Dim As UDT4 u40, u4
Print "Three-Level Inheritance (UDT1 <- UDT2 <- UDT3 <- UDT4):"

u4 = u40
u4 = Type<UDT4>(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
Print "  Type<UDT4>(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)  => OK"
Print "    UDT1: "; u4.I11; u4.I12
Print "    UDT2: "; u4.I21; u4.I22; u4.I23; u4.I24
Print "    UDT3: "; u4.I31; u4.I32; u4.I33
Print "    UDT4: "; u4.I41

u4 = u40
u4 = Type<UDT4>(Type<UDT3>(1, 2, 3, 4, 5, 6, 7, 8, 9), 10)
Print "  Type<UDT4>(Type<UDT3>(1, 2, 3, 4, 5, 6, 7, 8, 9), 10)  => NOK"
Print "    UDT1: "; u4.I11; u4.I12
Print "    UDT2: "; u4.I21; u4.I22; u4.I23; u4.I24
Print "    UDT3: "; u4.I31; u4.I32; u4.I33
Print "    UDT4: "; u4.I41

u4 = u40
u4 = Type<UDT4>(Type<UDT3>(Type<UDT2>(1, 2, 3, 4, 5, 6), 7, 8, 9), 10)
Print "  Type<UDT4>(Type<UDT3>(Type<UDT2>(1, 2, 3, 4, 5, 6), 7, 8, 9), 10)  => NOK"
Print "    UDT1: "; u4.I11; u4.I12
Print "    UDT2: "; u4.I21; u4.I22; u4.I23; u4.I24
Print "    UDT3: "; u4.I31; u4.I32; u4.I33
Print "    UDT4: "; u4.I41

u4 = u40
u4 = Type<UDT4>(Type<UDT3>(Type<UDT2>(Type<UDT1>(1, 2), 3, 4, 5, 6), 7, 8, 9), 10)
Print "  Type<UDT4>(Type<UDT3>(Type<UDT2>(Type<UDT1>(1, 2), 3, 4, 5, 6), 7, 8, 9), 10)  => NOK"
Print "    UDT1: "; u4.I11; u4.I12
Print "    UDT2: "; u4.I21; u4.I22; u4.I23; u4.I24
Print "    UDT3: "; u4.I31; u4.I32; u4.I33
Print "    UDT4: "; u4.I41

u4 = u40
u4 = Type<UDT4>(u3, 10)
Print "  Type<UDT4>(u3, 10)  => NOK"
Print "    UDT1: "; u4.I11; u4.I12
Print "    UDT2: "; u4.I21; u4.I22; u4.I23; u4.I24
Print "    UDT3: "; u4.I31; u4.I32; u4.I33
Print "    UDT4: "; u4.I41

u4 = u40
u4 = Type<UDT4>(Type<UDT3>(u2, 7, 8, 9), 10)
Print "  Type<UDT4>(Type<UDT3>(u2, 7, 8, 9), 10)  => NOK"
Print "    UDT1: "; u4.I11; u4.I12
Print "    UDT2: "; u4.I21; u4.I22; u4.I23; u4.I24
Print "    UDT3: "; u4.I31; u4.I32; u4.I33
Print "    UDT4: "; u4.I41

u4 = u40
u4 = Type<UDT4>(Type<UDT3>(Type<UDT2>(u1, 3, 4, 5, 6), 7, 8, 9), 10)
Print "  Type<UDT4>(Type<UDT3>(Type<UDT2>(u1, 3, 4, 5, 6), 7, 8, 9), 10)  => NOK"
Print "    UDT1: "; u4.I11; u4.I12
Print "    UDT2: "; u4.I21; u4.I22; u4.I23; u4.I24
Print "    UDT3: "; u4.I31; u4.I32; u4.I33
Print "    UDT4: "; u4.I41

Sleep
  • Output:

    Code: Select all

    No Inheritance (UDT1)
      u1 = Type<UDT1>(1, 2)  => OK
        UDT1:  1 2
    
    Single Inheritance (UDT1 <- UDT2):
      Type<UDT2>(1, 2, 3, 4, 5, 6)  => OK
        UDT1:  1 2
        UDT2:  3 4 5 6
      Type<UDT2>(Type<UDT1>(1, 2), 3, 4, 5, 6)  => OK
        UDT1:  1 2
        UDT2:  3 4 5 6
      Type<UDT2>(u1, 3, 4, 5, 6)  => OK
        UDT1:  1 2
        UDT2:  3 4 5 6
    
    Two-Level Inheritance (UDT1 <- UDT2 <- UDT3):
      Type<UDT3>(1, 2, 3, 4, 5, 6, 7, 8, 9)  => OK
        UDT1:  1 2
        UDT2:  3 4 5 6
        UDT3:  7 8 9
      Type<UDT3>(Type<UDT2>(1, 2, 3, 4, 5, 6), 7, 8, 9)  => NOK
        UDT1:  1 2
        UDT2:  7 8 9 0
        UDT3:  0 0 0
      Type<UDT3>(Type<UDT2>(Type<UDT1>(1, 2), 3, 4, 5, 6), 7, 8, 9)  => NOK
        UDT1:  1 2
        UDT2:  7 8 9 0
        UDT3:  0 0 0
      Type<UDT3>(u2, 7, 8, 9)  => NOK
        UDT1:  1 2
        UDT2:  7 8 9 0
        UDT3:  0 0 0
      Type<UDT3>(Type<UDT2>(u1, 3, 4, 5, 6), 7, 8, 9)  => NOK
        UDT1:  1 2
        UDT2:  7 8 9 0
        UDT3:  0 0 0
    
    Three-Level Inheritance (UDT1 <- UDT2 <- UDT3 <- UDT4):
      Type<UDT4>(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)  => OK
        UDT1:  1 2
        UDT2:  3 4 5 6
        UDT3:  7 8 9
        UDT4:  10
      Type<UDT4>(Type<UDT3>(1, 2, 3, 4, 5, 6, 7, 8, 9), 10)  => NOK
        UDT1:  1 2
        UDT2:  10 0 0 0
        UDT3:  0 0 0
        UDT4:  0
      Type<UDT4>(Type<UDT3>(Type<UDT2>(1, 2, 3, 4, 5, 6), 7, 8, 9), 10)  => NOK
        UDT1:  1 2
        UDT2:  10 0 0 0
        UDT3:  0 0 0
        UDT4:  0
      Type<UDT4>(Type<UDT3>(Type<UDT2>(Type<UDT1>(1, 2), 3, 4, 5, 6), 7, 8, 9), 10)  => NOK
        UDT1:  1 2
        UDT2:  10 0 0 0
        UDT3:  0 0 0
        UDT4:  0
      Type<UDT4>(u3, 10)  => NOK
        UDT1:  1 2
        UDT2:  10 0 0 0
        UDT3:  0 0 0
        UDT4:  0
      Type<UDT4>(Type<UDT3>(u2, 7, 8, 9), 10)  => NOK
        UDT1:  1 2
        UDT2:  10 0 0 0
        UDT3:  0 0 0
        UDT4:  0
      Type<UDT4>(Type<UDT3>(Type<UDT2>(u1, 3, 4, 5, 6), 7, 8, 9), 10)  => NOK
        UDT1:  1 2
        UDT2:  10 0 0 0
        UDT3:  0 0 0
        UDT4:  0

In the failing cases, only the data members of the topmost Base (UDT1 in the example above) are correctly initialized.
fxm
Moderator
Posts: 11420
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Nesting TYPE (temporary) keyword does not support multi-level inheritance structure

Post by fxm »

This only works well in all cases if one defines at least 3 mandatory explicit constructors in UDT3 and 3 other mandatory explicit constructors in UDT4:

Code: Select all

Type UDT1
    Dim As Integer I11, I12
'    Declare Constructor()
'    Declare Constructor(Byval i1 As Integer, Byval i2 As Integer)
End Type

'Constructor UDT1()
'End Constructor

'Constructor UDT1(Byval i1 As Integer, Byval i2 As Integer)
'    This.I11 = i1 : This.I12 = i2
'End Constructor

Type UDT2 Extends UDT1
    Dim As Integer I21, I22, I23, I24
'    Declare Constructor()
'    Declare Constructor(Byval i1 As Integer, Byval i2 As Integer, Byval i3 As Integer, Byval i4 As Integer, Byval i5 As Integer, Byval i6 As Integer)
'    Declare Constructor(Byref u1 As UDT1, Byval i3 As Integer, Byval i4 As Integer, Byval i5 As Integer, Byval i6 As Integer)
End Type

'Constructor UDT2()
'End Constructor

'Constructor UDT2(Byval i1 As Integer, Byval i2 As Integer, Byval i3 As Integer, Byval i4 As Integer, Byval i5 As Integer, Byval i6 As Integer)
'    This.I11 = i1 : This.I12 = i2 : This.I21 = i3 : This.I22 = i4 : This.I23 = i5 : This.I24 = i6
'End Constructor

'Constructor UDT2(Byref u1 As UDT1, Byval i3 As Integer, Byval i4 As Integer, Byval i5 As Integer, Byval i6 As Integer)
'    Cast(UDT1, This) = u1 : This.I21 = i3 : This.I22 = i4 : This.I23 = i5 : This.I24 = i6
'End Constructor

Type UDT3 Extends UDT2
    Dim As Integer I31, I32, I33
    Declare Constructor()
    Declare Constructor(Byval i1 As Integer, Byval i2 As Integer, Byval i3 As Integer, Byval i4 As Integer, Byval i5 As Integer, Byval i6 As Integer, Byval i7 As Integer, Byval i8 As Integer, Byval i9 As Integer)
    Declare Constructor(Byref u2 As UDT2, Byval i7 As Integer, Byval i8 As Integer, Byval i9 As Integer)
End Type

Constructor UDT3()
End Constructor

Constructor UDT3(Byval i1 As Integer, Byval i2 As Integer, Byval i3 As Integer, Byval i4 As Integer, Byval i5 As Integer, Byval i6 As Integer, Byval i7 As Integer, Byval i8 As Integer, Byval i9 As Integer)
    This.I11 = i1 : This.I12 = i2 : This.I21 = i3 : This.I22 = i4 : This.I23 = i5 : This.I24 = i6 : This.I31 = i7 : This.I32 = i8 : This.I33 = i9
End Constructor

Constructor UDT3(Byref u2 As UDT2, Byval i7 As Integer, Byval i8 As Integer, Byval i9 As Integer)
    Cast(UDT2, This) = u2 : This.I31 = i7 : This.I32 = i8 : This.I33 = i9
End Constructor

Type UDT4 Extends UDT3
    Dim As Integer I41
    Declare Constructor()
    Declare Constructor(Byval i1 As Integer, Byval i2 As Integer, Byval i3 As Integer, Byval i4 As Integer, Byval i5 As Integer, Byval i6 As Integer, Byval i7 As Integer, Byval i8 As Integer, Byval i9 As Integer, Byval i10 As Integer)
    Declare Constructor(Byref u3 As UDT3, Byval i10 As Integer)
End Type

Constructor UDT4()
End Constructor

Constructor UDT4(Byval i1 As Integer, Byval i2 As Integer, Byval i3 As Integer, Byval i4 As Integer, Byval i5 As Integer, Byval i6 As Integer, Byval i7 As Integer, Byval i8 As Integer, Byval i9 As Integer, Byval i10 As Integer)
    This.I11 = i1 : This.I12 = i2 : This.I21 = i3 : This.I22 = i4 : This.I23 = i5 : This.I24 = i6 : This.I31 = i7 : This.I32 = i8 : This.I33 = i9 : This.I41 = i10
End Constructor

Constructor UDT4(Byref u3 As UDT3, Byval i10 As Integer)
    Cast(UDT3, This) = u3 : This.I41 = i10
End Constructor

Dim As UDT1 u1
Print "No Inheritance (UDT1)"

u1 = Type<UDT1>(1, 2)
Print "  u1 = Type<UDT1>(1, 2)  => OK"
Print "    UDT1: "; u1.I11; u1.I12

Print
Dim As UDT2 u20, u2
Print "Single Inheritance (UDT1 <- UDT2):"

u2 = u20
u2 = Type<UDT2>(1, 2, 3, 4, 5, 6)
print "  Type<UDT2>(1, 2, 3, 4, 5, 6)  => OK"
Print "    UDT1: "; u2.I11; u2.I12
Print "    UDT2: "; u2.I21; u2.I22; u2.I23; u2.I24

u2 = u20
u2 = Type<UDT2>(Type<UDT1>(1, 2), 3, 4, 5, 6)
Print "  Type<UDT2>(Type<UDT1>(1, 2), 3, 4, 5, 6)  => OK"
Print "    UDT1: "; u2.I11; u2.I12
Print "    UDT2: "; u2.I21; u2.I22; u2.I23; u2.I24

u2 = u20
u2 = Type<UDT2>(u1, 3, 4, 5, 6)
Print "  Type<UDT2>(u1, 3, 4, 5, 6)  => OK"
Print "    UDT1: "; u2.I11; u2.I12
Print "    UDT2: "; u2.I21; u2.I22; u2.I23; u2.I24

u2 = Type<UDT2>(1, 2, 3, 4, 5, 6)

Print
Dim As UDT3 u30, u3
Print "Two-Level Inheritance (UDT1 <- UDT2 <- UDT3):"

u3 = u30
u3 = Type<UDT3>(1, 2, 3, 4, 5, 6, 7, 8, 9)
Print "  Type<UDT3>(1, 2, 3, 4, 5, 6, 7, 8, 9)  => OK"
Print "    UDT1: "; u3.I11; u3.I12
Print "    UDT2: "; u3.I21; u3.I22; u3.I23; u3.I24
Print "    UDT3: "; u3.I31; u3.I32; u3.I33

u3 = u30
u3 = Type<UDT3>(Type<UDT2>(1, 2, 3, 4, 5, 6), 7, 8, 9)
Print "  Type<UDT3>(Type<UDT2>(1, 2, 3, 4, 5, 6), 7, 8, 9)  => OK"
Print "    UDT1: "; u3.I11; u3.I12
Print "    UDT2: "; u3.I21; u3.I22; u3.I23; u3.I24
Print "    UDT3: "; u3.I31; u3.I32; u3.I33

u3 = u30
u3 = Type<UDT3>(Type<UDT2>(Type<UDT1>(1, 2), 3, 4, 5, 6), 7, 8, 9)
Print "  Type<UDT3>(Type<UDT2>(Type<UDT1>(1, 2), 3, 4, 5, 6), 7, 8, 9)  => OK"
Print "    UDT1: "; u3.I11; u3.I12
Print "    UDT2: "; u3.I21; u3.I22; u3.I23; u3.I24
Print "    UDT3: "; u3.I31; u3.I32; u3.I33

u3 = u30
u3 = Type<UDT3>(u2, 7, 8, 9)
Print "  Type<UDT3>(u2, 7, 8, 9)  => OK"
Print "    UDT1: "; u3.I11; u3.I12
Print "    UDT2: "; u3.I21; u3.I22; u3.I23; u3.I24
Print "    UDT3: "; u3.I31; u3.I32; u3.I33

u3 = u30
u3 = Type<UDT3>(Type<UDT2>(u1, 3, 4, 5, 6), 7, 8, 9)
Print "  Type<UDT3>(Type<UDT2>(u1, 3, 4, 5, 6), 7, 8, 9)  => OK"
Print "    UDT1: "; u3.I11; u3.I12
Print "    UDT2: "; u3.I21; u3.I22; u3.I23; u3.I24
Print "    UDT3: "; u3.I31; u3.I32; u3.I33

u3 = Type<UDT3>(1, 2, 3, 4, 5, 6, 7, 8, 9)

Print
Dim As UDT4 u40, u4
Print "Three-Level Inheritance (UDT1 <- UDT2 <- UDT3 <- UDT4):"

u4 = u40
u4 = Type<UDT4>(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
Print "  Type<UDT4>(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)  => OK"
Print "    UDT1: "; u4.I11; u4.I12
Print "    UDT2: "; u4.I21; u4.I22; u4.I23; u4.I24
Print "    UDT3: "; u4.I31; u4.I32; u4.I33
Print "    UDT4: "; u4.I41

u4 = u40
u4 = Type<UDT4>(Type<UDT3>(1, 2, 3, 4, 5, 6, 7, 8, 9), 10)
Print "  Type<UDT4>(Type<UDT3>(1, 2, 3, 4, 5, 6, 7, 8, 9), 10)  => OK"
Print "    UDT1: "; u4.I11; u4.I12
Print "    UDT2: "; u4.I21; u4.I22; u4.I23; u4.I24
Print "    UDT3: "; u4.I31; u4.I32; u4.I33
Print "    UDT4: "; u4.I41

u4 = u40
u4 = Type<UDT4>(Type<UDT3>(Type<UDT2>(1, 2, 3, 4, 5, 6), 7, 8, 9), 10)
Print "  Type<UDT4>(Type<UDT3>(Type<UDT2>(1, 2, 3, 4, 5, 6), 7, 8, 9), 10)  => OK"
Print "    UDT1: "; u4.I11; u4.I12
Print "    UDT2: "; u4.I21; u4.I22; u4.I23; u4.I24
Print "    UDT3: "; u4.I31; u4.I32; u4.I33
Print "    UDT4: "; u4.I41

u4 = u40
u4 = Type<UDT4>(Type<UDT3>(Type<UDT2>(Type<UDT1>(1, 2), 3, 4, 5, 6), 7, 8, 9), 10)
Print "  Type<UDT4>(Type<UDT3>(Type<UDT2>(Type<UDT1>(1, 2), 3, 4, 5, 6), 7, 8, 9), 10)  => OK"
Print "    UDT1: "; u4.I11; u4.I12
Print "    UDT2: "; u4.I21; u4.I22; u4.I23; u4.I24
Print "    UDT3: "; u4.I31; u4.I32; u4.I33
Print "    UDT4: "; u4.I41

u4 = u40
u4 = Type<UDT4>(u3, 10)
Print "  Type<UDT4>(u3, 10)  => OK"
Print "    UDT1: "; u4.I11; u4.I12
Print "    UDT2: "; u4.I21; u4.I22; u4.I23; u4.I24
Print "    UDT3: "; u4.I31; u4.I32; u4.I33
Print "    UDT4: "; u4.I41

u4 = u40
u4 = Type<UDT4>(Type<UDT3>(u2, 7, 8, 9), 10)
Print "  Type<UDT4>(Type<UDT3>(u2, 7, 8, 9), 10)  => OK"
Print "    UDT1: "; u4.I11; u4.I12
Print "    UDT2: "; u4.I21; u4.I22; u4.I23; u4.I24
Print "    UDT3: "; u4.I31; u4.I32; u4.I33
Print "    UDT4: "; u4.I41

u4 = u40
u4 = Type<UDT4>(Type<UDT3>(Type<UDT2>(u1, 3, 4, 5, 6), 7, 8, 9), 10)
Print "  Type<UDT4>(Type<UDT3>(Type<UDT2>(u1, 3, 4, 5, 6), 7, 8, 9), 10)  => OK"
Print "    UDT1: "; u4.I11; u4.I12
Print "    UDT2: "; u4.I21; u4.I22; u4.I23; u4.I24
Print "    UDT3: "; u4.I31; u4.I32; u4.I33
Print "    UDT4: "; u4.I41

Sleep
  • Output:

    Code: Select all

    No Inheritance (UDT1)
      u1 = Type<UDT1>(1, 2)  => OK
        UDT1:  1 2
    
    Single Inheritance (UDT1 <- UDT2):
      Type<UDT2>(1, 2, 3, 4, 5, 6)  => OK
        UDT1:  1 2
        UDT2:  3 4 5 6
      Type<UDT2>(Type<UDT1>(1, 2), 3, 4, 5, 6)  => OK
        UDT1:  1 2
        UDT2:  3 4 5 6
      Type<UDT2>(u1, 3, 4, 5, 6)  => OK
        UDT1:  1 2
        UDT2:  3 4 5 6
    
    Two-Level Inheritance (UDT1 <- UDT2 <- UDT3):
      Type<UDT3>(1, 2, 3, 4, 5, 6, 7, 8, 9)  => OK
        UDT1:  1 2
        UDT2:  3 4 5 6
        UDT3:  7 8 9
      Type<UDT3>(Type<UDT2>(1, 2, 3, 4, 5, 6), 7, 8, 9)  => OK
        UDT1:  1 2
        UDT2:  3 4 5 6
        UDT3:  7 8 9
      Type<UDT3>(Type<UDT2>(Type<UDT1>(1, 2), 3, 4, 5, 6), 7, 8, 9)  => OK
        UDT1:  1 2
        UDT2:  3 4 5 6
        UDT3:  7 8 9
      Type<UDT3>(u2, 7, 8, 9)  => OK
        UDT1:  1 2
        UDT2:  3 4 5 6
        UDT3:  7 8 9
      Type<UDT3>(Type<UDT2>(u1, 3, 4, 5, 6), 7, 8, 9)  => OK
        UDT1:  1 2
        UDT2:  3 4 5 6
        UDT3:  7 8 9
    
    Three-Level Inheritance (UDT1 <- UDT2 <- UDT3 <- UDT4):
      Type<UDT4>(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)  => OK
        UDT1:  1 2
        UDT2:  3 4 5 6
        UDT3:  7 8 9
        UDT4:  10
      Type<UDT4>(Type<UDT3>(1, 2, 3, 4, 5, 6, 7, 8, 9), 10)  => OK
        UDT1:  1 2
        UDT2:  3 4 5 6
        UDT3:  7 8 9
        UDT4:  10
      Type<UDT4>(Type<UDT3>(Type<UDT2>(1, 2, 3, 4, 5, 6), 7, 8, 9), 10)  => OK
        UDT1:  1 2
        UDT2:  3 4 5 6
        UDT3:  7 8 9
        UDT4:  10
      Type<UDT4>(Type<UDT3>(Type<UDT2>(Type<UDT1>(1, 2), 3, 4, 5, 6), 7, 8, 9), 10)  => OK
        UDT1:  1 2
        UDT2:  3 4 5 6
        UDT3:  7 8 9
        UDT4:  10
      Type<UDT4>(u3, 10)  => OK
        UDT1:  1 2
        UDT2:  3 4 5 6
        UDT3:  7 8 9
        UDT4:  10
      Type<UDT4>(Type<UDT3>(u2, 7, 8, 9), 10)  => OK
        UDT1:  1 2
        UDT2:  3 4 5 6
        UDT3:  7 8 9
        UDT4:  10
      Type<UDT4>(Type<UDT3>(Type<UDT2>(u1, 3, 4, 5, 6), 7, 8, 9), 10)  => OK
        UDT1:  1 2
        UDT2:  3 4 5 6
        UDT3:  7 8 9
        UDT4:  10
    
fxm
Moderator
Posts: 11420
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Nesting TYPE (temporary) keyword does not support multi-level inheritance structure

Post by fxm »

Similar default when a constructor of a derived-type calls (using the BASE keyword) the implicit copy-constructor of its base:
This implicit copy-construct only copies the data members of the topmost base.

- Example for a two-level inheritance structure (UDT1 <- UDT2 <- UDT3):

Code: Select all

Type UDT1
    Dim As Integer I11, I12
End Type

Type UDT2 Extends UDT1
    Dim As Integer I21, I22, I23, I24
'    Declare Constructor()
'    Declare Constructor(Byref u2 As UDT2)
End Type

'Constructor UDT2()
'End Constructor

'Constructor UDT2(Byref u2 As UDT2)
'    This = u2
'End Constructor

Type UDT3 Extends UDT2
    Dim As Integer I31, I32, I33
    Declare Constructor(Byref u2 As UDT2, Byval i7 As Integer, Byval i8 As Integer, Byval i9 As Integer)
End Type

Constructor UDT3(Byref u2 As UDT2, Byval i7 As Integer, Byval i8 As Integer, Byval i9 As Integer)
    Base(u2)
'    Cast(UDT2, This) = u2
    This.I31 = i7 : This.I32 = i8 : This.I33 = i9
End Constructor

Dim As UDT2 u21
u21.I11 = 1 : u21.I12 = 2 : u21.I21 = 3 : u21.I22 = 4 : u21.I23 = 5 : u21.I24 = 6
Print "u21:"
Print "  UDT1: "; u21.I11; u21.I12
Print "  UDT2: "; u21.I21; u21.I22; u21.I23; u21.I24
Print

Dim As UDT2 u2 = u21
Print "Dim As UDT2 u2 = u21  => OK"
Print "  UDT1: "; u2.I11; u2.I12
Print "  UDT2: "; u2.I21; u2.I22; u2.I23; u2.I24

Print
Dim As UDT3 u3 = UDT3(u21, 7, 8, 9)
Print "Dim As UDT3 u3 = UDT3(u21, 7, 8, 9)  => NOK"
Print "  UDT1: "; u3.I11; u3.I12
Print "  UDT2: "; u3.I21; u3.I22; u3.I23; u3.I24
Print "  UDT3: "; u3.I31; u3.I32; u3.I33

Sleep
  • Output:

    Code: Select all

    u21:
      UDT1:  1 2
      UDT2:  3 4 5 6
    
    Dim As UDT2 u2 = u21  => OK
      UDT1:  1 2
      UDT2:  3 4 5 6
    
    Dim As UDT3 u3 = UDT3(u21, 7, 8, 9)  => NOK
      UDT1:  1 2
      UDT2:  0 0 0 0
      UDT3:  7 8 9
    
- Example for a three-level inheritance structure (UDT1 <- UDT2 <- UDT3 <- UDT4):

Code: Select all

Type UDT1
    Dim As Integer I11, I12
End Type

Type UDT2 Extends UDT1
    Dim As Integer I21, I22, I23, I24
End Type

Type UDT3 Extends UDT2
    Dim As Integer I31, I32, I33
'    Declare Constructor()
'    Declare Constructor(Byref u3 As UDT3)
End Type

'Constructor UDT3()
'End Constructor

'Constructor UDT3(Byref u3 As UDT3)
'    This = u3
'End Constructor

Type UDT4 Extends UDT3
    Dim As Integer I41
    Declare Constructor(Byref u3 As UDT3, Byval i10 As Integer)
End Type

Constructor UDT4(Byref u3 As UDT3, Byval i10 As Integer)
    Base(u3)
'    Cast(UDT3, This) = u3
    This.I41 = i10
End Constructor

Dim As UDT3 u31
u31.I11 = 1 : u31.I12 = 2 : u31.I21 = 3 : u31.I22 = 4 : u31.I23 = 5 : u31.I24 = 6 : u31.I31 = 7 : u31.I32 = 8 : u31.I33 = 9
Print "u31:"
Print "  UDT1: "; u31.I11; u31.I12
Print "  UDT2: "; u31.I21; u31.I22; u31.I23; u31.I24
Print "  UDT3: "; u31.I31; u31.I32; u31.I33
Print

Dim As UDT3 u3 = u31
Print "Dim As UDT3 u3 = u31  => OK"
Print "  UDT1: "; u3.I11; u3.I12
Print "  UDT2: "; u3.I21; u3.I22; u3.I23; u3.I24
Print "  UDT3: "; u3.I31; u3.I32; u3.I33

Print
Dim As UDT4 u4 = UDT4(u31, 10)
Print "Dim As UDT4 u4 = UDT4(u31, 10)  => NOK"
Print "  UDT1: "; u4.I11; u4.I12
Print "  UDT2: "; u4.I21; u4.I22; u4.I23; u4.I24
Print "  UDT3: "; u4.I31; u4.I32; u4.I33
Print "  UDT4: "; u4.I41

Sleep
  • Output:

    Code: Select all

    u31:
      UDT1:  1 2
      UDT2:  3 4 5 6
      UDT3:  7 8 9
    
    Dim As UDT3 u3 = u31  => OK
      UDT1:  1 2
      UDT2:  3 4 5 6
      UDT3:  7 8 9
    
    Dim As UDT4 u4 = UDT4(u31, 10)  => NOK
      UDT1:  1 2
      UDT2:  0 0 0 0
      UDT3:  0 0 0
      UDT4:  10
    

If the implicit copy-assignment operator of its base is called instead of the implicit copy-constructor (using the CAST keyword to up-cast THIS), this works well then:
- replace 'Base(u2)' with 'Cast(UDT2, This) = u2' in the first code above, and 'Base(u3)' with 'Cast(UDT3, This) = u3' in the second code above.

If an explicit copy-constructor of its base is defined, this also works well:
- constructor definitions to uncomment in the two codes above (in UDT2 for the first code and in UDT3 for the second code).
fxm
Moderator
Posts: 11420
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Nesting TYPE (temporary) keyword does not support multi-level inheritance structure

Post by fxm »

In summary, the weird behavior or defect or bug is more precisely the following for all these cases:

- The implicit copy-constructor of a type, when called from a derived-type, only copies the data members of the topmost base.
  • Examples:
    - 'Base(u30)' in the UDT4 constructor
    (from the post above)
    - 'u4 = Type<UDT4>(Type<UDT3>(1, 2, 3, 4, 5, 6, 7, 8, 9), 10)'
    or 'u4 = Type<UDT4>(u3, 10)' (from the first post)
    (these 3 syntaxes call the implicit copy-constructor of UDT3 from a UDT4 instance)

    But when the implicit copy-constructor of a type is called to copy-construct an instance of this same type for simple cloning, this works well.
    • Example: 'Dim As UDT3 u3 = u30' (from the post above)
      (this syntax calls the implicit copy-constructor of UDT3 from a UDT3 instance)
    When using an explicit copy-constructor, this works well.

- In contrast to the implicit copy-constructor, the implicit copy-assignment operator, when called from a derived-type, does correctly copy the data members of all its bases.
  • Example: 'Cast(UDT3, This) = u30' in the UDT4 constructor (from the post above)
    (this syntax calls the implicit copy-assignment operator of UDT3 from a UDT4 instance)
fxm
Moderator
Posts: 11420
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Using TYPE() or BASE() on derived instance, implicit copy/construct only copies data members of topmost base

Post by fxm »

Continuation of the analysis, and synthesis (analysis progressing step by step)

Returning also to the case of the TYPE (temporary) keyword, we see that the defect exists even while remaining at the same level of derived-type.

Synthesis example for all the types of defect:

Code: Select all

Type UDT1
    Dim As Integer I11, I12
End Type

Type UDT2 Extends UDT1
    Dim As Integer I21, I22, I23, I24
End Type

Type UDT3 Extends UDT2
    Dim As Integer I31, I32, I33
'    Declare Constructor()
'    Declare Constructor(Byref u3 As UDT3)
'    Declare Constructor(Byref u2 As UDT2, Byval i7 As Integer = 0, Byval i8 As Integer = 0, Byval i9 As Integer = 0)
End Type

'Constructor UDT3()
'End Constructor

'Constructor UDT3(Byref u3 As UDT3)
'    This = u3
'End Constructor

'Constructor UDT3(Byref u2 As UDT2, Byval i7 As Integer = 0, Byval i8 As Integer = 0, Byval i9 As Integer = 0)
'    Cast(UDT2, This) = u2
'    This.I31 = i7 : This.I32 = i8 : This.I33 = i9
'End Constructor

Type UDT4 Extends UDT3
    Dim As Integer I41
    Declare Constructor()
    Declare Constructor(Byref u3 As UDT3, Byval i10 As Integer)
End Type

Constructor UDT4()
End Constructor

Constructor UDT4(Byref u3 As UDT3, Byval i10 As Integer)
    Base(u3)
'    Cast(UDT3, This) = u3
    This.I41 = i10
End Constructor

Dim As UDT2 u21 = Type<UDT2>(1, 2, 3, 4, 5, 6)
Print "Dim As UDT2 u21 = Type<UDT2>(1, 2, 3, 4, 5, 6)  => OK"
Print "  UDT1: "; u21.I11; u21.I12
Print "  UDT2: "; u21.I21; u21.I22; u21.I23; u21.I24
Print

Dim As UDT3 u31
Cast(UDT2, u31) = u21 : u31.I31 = 7 : u31.I32 = 8 : u31.I33 = 9
Print "Cast(UDT2, u31) = u21 : u31.I31 = 7 : u31.I32 = 8 : u31.I33 = 9  => OK"
Print "  UDT1: "; u31.I11; u31.I12
Print "  UDT2: "; u31.I21; u31.I22; u31.I23; u31.I24
Print "  UDT3: "; u31.I31; u31.I32; u31.I33
Print

Dim As UDT3 u32 = u31
Print "Dim As UDT3 u32 = u31  => OK"
Print "  UDT1: "; u32.I11; u32.I12
Print "  UDT2: "; u32.I21; u32.I22; u32.I23; u32.I24
Print "  UDT3: "; u32.I31; u32.I32; u32.I33
Print

Dim As UDT3 u33 = Type<UDT3>(u31)
Print "Dim As UDT3 u33 = Type<UDT3>(u31)  => NOK"
Print "  UDT1: "; u33.I11; u33.I12
Print "  UDT2: "; u33.I21; u33.I22; u33.I23; u33.I24
Print "  UDT3: "; u33.I31; u33.I32; u33.I33
Print

Dim As UDT3 u34
u34 = u31
Print "u34 = u31  => OK"
Print "  UDT1: "; u34.I11; u34.I12
Print "  UDT2: "; u34.I21; u34.I22; u34.I23; u34.I24
Print "  UDT3: "; u34.I31; u34.I32; u34.I33
Print

Dim As UDT3 u35
u35 = Type<UDT3>(u31)
Print "u35 = Type<UDT3>(u31)  => NOK"
Print "  UDT1: "; u35.I11; u35.I12
Print "  UDT2: "; u35.I21; u35.I22; u35.I23; u35.I24
Print "  UDT3: "; u35.I31; u35.I32; u35.I33
Print

Dim As UDT3 u36
u36 = Type<UDT3>(u21)
Print "u36 = Type<UDT3>(u21)  => NOK"
Print "  UDT1: "; u36.I11; u36.I12
Print "  UDT2: "; u36.I21; u36.I22; u36.I23; u36.I24
Print "  UDT3: "; u36.I31; u36.I32; u36.I33
Print

Dim As UDT3 u37 = Type<UDT3>(u21)
Print "Dim As UDT3 u37 = Type<UDT3>(u21)  => NOK"
Print "  UDT1: "; u37.I11; u37.I12
Print "  UDT2: "; u37.I21; u37.I22; u37.I23; u37.I24
Print "  UDT3: "; u37.I31; u37.I32; u37.I33
Print

Dim As UDT3 u38
u38 = Type<UDT3>(u21, 7, 8, 9)
Print "u38 = Type<UDT3>(u21, 7, 8, 9)  => NOK"
Print "  UDT1: "; u38.I11; u38.I12
Print "  UDT2: "; u38.I21; u38.I22; u38.I23; u38.I24
Print "  UDT3: "; u38.I31; u38.I32; u38.I33
Print

Dim As UDT3 u39 = Type<UDT3>(u21, 7, 8, 9)
Print "Dim As UDT3 u39 = Type<UDT3>(u21, 7, 8, 9)  => NOK"
Print "  UDT1: "; u39.I11; u39.I12
Print "  UDT2: "; u39.I21; u39.I22; u39.I23; u39.I24
Print "  UDT3: "; u39.I31; u39.I32; u39.I33
Print

Dim As UDT3 u3A
u3A = Type<UDT3>(Type<UDT2>(1, 2, 3, 4, 5, 6), 7, 8, 9)
Print "u3A = Type<UDT3>(Type<UDT2>(1, 2, 3, 4, 5, 6), 7, 8, 9)  => NOK"
Print "  UDT1: "; u3A.I11; u3A.I12
Print "  UDT2: "; u3A.I21; u3A.I22; u3A.I23; u3A.I24
Print "  UDT3: "; u3A.I31; u3A.I32; u3A.I33
Print

Dim As UDT3 u3B = Type<UDT3>(Type<UDT2>(1, 2, 3, 4, 5, 6), 7, 8, 9)
Print "Dim As UDT3 u3B = Type<UDT3>(Type<UDT2>(1, 2, 3, 4, 5, 6), 7, 8, 9)  => NOK"
Print "  UDT1: "; u3B.I11; u3B.I12
Print "  UDT2: "; u3B.I21; u3B.I22; u3B.I23; u3B.I24
Print "  UDT3: "; u3B.I31; u3B.I32; u3B.I33
Print

Dim As UDT3 u3C
u3C = Type<UDT3>(Type<UDT2>(Type<UDT1>(1, 2), 3, 4, 5, 6), 7, 8, 9)
Print "u3C = Type<UDT3>(Type<UDT2>(Type<UDT1>(1, 2), 3, 4, 5, 6), 7, 8, 9)  => NOK"
Print "  UDT1: "; u3C.I11; u3C.I12
Print "  UDT2: "; u3C.I21; u3C.I22; u3C.I23; u3C.I24
Print "  UDT3: "; u3C.I31; u3C.I32; u3C.I33
Print

Dim As UDT3 u3D = Type<UDT3>(Type<UDT2>(Type<UDT1>(1, 2), 3, 4, 5, 6), 7, 8, 9)
Print "Dim As UDT3 u3D = Type<UDT3>(Type<UDT2>(Type<UDT1>(1, 2), 3, 4, 5, 6), 7, 8, 9)  => NOK"
Print "  UDT1: "; u3D.I11; u3D.I12
Print "  UDT2: "; u3D.I21; u3D.I22; u3D.I23; u3D.I24
Print "  UDT3: "; u3D.I31; u3D.I32; u3D.I33
Print

Dim As UDT4 u41 =  UDT4(u31, 10)
Print "Dim As UDT4 u41 =  UDT4(u31, 10)  => Base(u31) in UDT4 constructor  => NOK"
Print "  UDT1: "; u41.I11; u41.I12
Print "  UDT2: "; u41.I21; u41.I22; u41.I23; u41.I24
Print "  UDT3: "; u41.I31; u41.I32; u41.I33
Print "  UDT4: "; u41.I41
Print

Sleep
  • Output:

    Code: Select all

    Dim As UDT2 u21 = Type<UDT2>(1, 2, 3, 4, 5, 6)  => OK
      UDT1:  1 2
      UDT2:  3 4 5 6
    
    Cast(UDT2, u31) = u21 : u31.I31 = 7 : u31.I32 = 8 : u31.I33 = 9  => OK
      UDT1:  1 2
      UDT2:  3 4 5 6
      UDT3:  7 8 9
    
    Dim As UDT3 u32 = u31  => OK
      UDT1:  1 2
      UDT2:  3 4 5 6
      UDT3:  7 8 9
    
    Dim As UDT3 u33 = Type<UDT3>(u31)  => NOK
      UDT1:  1 2
      UDT2:  0 0 0 0
      UDT3:  0 0 0
    
    u34 = u31  => OK
      UDT1:  1 2
      UDT2:  3 4 5 6
      UDT3:  7 8 9
    
    u35 = Type<UDT3>(u31)  => NOK
      UDT1:  1 2
      UDT2:  0 0 0 0
      UDT3:  0 0 0
    
    u36 = Type<UDT3>(u21)  => NOK
      UDT1:  1 2
      UDT2:  0 0 0 0
      UDT3:  0 0 0
    
    Dim As UDT3 u37 = Type<UDT3>(u21)  => NOK
      UDT1:  1 2
      UDT2:  0 0 0 0
      UDT3:  0 0 0
    
    u38 = Type<UDT3>(u21, 7, 8, 9)  => NOK
      UDT1:  1 2
      UDT2:  7 8 9 0
      UDT3:  0 0 0
    
    Dim As UDT3 u39 = Type<UDT3>(u21, 7, 8, 9)  => NOK
      UDT1:  1 2
      UDT2:  7 8 9 0
      UDT3:  0 0 0
    
    u3A = Type<UDT3>(Type<UDT2>(1, 2, 3, 4, 5, 6), 7, 8, 9)  => NOK
      UDT1:  1 2
      UDT2:  7 8 9 0
      UDT3:  0 0 0
    
    Dim As UDT3 u3B = Type<UDT3>(Type<UDT2>(1, 2, 3, 4, 5, 6), 7, 8, 9)  => NOK
      UDT1:  1 2
      UDT2:  7 8 9 0
      UDT3:  0 0 0
    
    u3C = Type<UDT3>(Type<UDT2>(Type<UDT1>(1, 2), 3, 4, 5, 6), 7, 8, 9)  => NOK
      UDT1:  1 2
      UDT2:  7 8 9 0
      UDT3:  0 0 0
    
    Dim As UDT3 u3D = Type<UDT3>(Type<UDT2>(Type<UDT1>(1, 2), 3, 4, 5, 6), 7, 8, 9)  => NOK
      UDT1:  1 2
      UDT2:  7 8 9 0
      UDT3:  0 0 0
    
    Dim As UDT4 u41 =  UDT4(u31, 10)  => Base(u31) in UDT4 constructor  => NOK
      UDT1:  1 2
      UDT2:  0 0 0 0
      UDT3:  0 0 0
      UDT4:  10
    

    Comments:
    • - Three-level inheritance structure (UDT1 <- UDT2 <-UDT3 <- UDT4), 'u21' being one instance of UDT2, 'u3x' being instances of UDT3, 'u41' one instance of UDT4, and constructors in UDT4 only (for the last test on 'Base()'):
      • - 'Dim As UDT2 u21 = Type<UDT2>(1, 2, 3, 4, 5, 6)' works well.
        - 'Cast(UDT2, u31) = u21 : u31.I31 = 7 : u31.I32 = 8 : u31.I33 = 9' works well.
        - 'Dim As UDT3 u32 = u31' works well, but 'Dim As UDT3 u33 = Type<UDT3>(u31)' does not work well.
        - 'u34 = u31' works well, but 'u35 = Type<UDT3>(u31)' does not work well.
        - 'u36 = Type<UDT3>(u21)' and 'Dim As UDT3 u37 = Type<UDT3>(u21)' do not work well.
        - 'u38 = Type<UDT3>(u21, 7, 8, 9)' and 'Dim As UDT3 u39 = Type<UDT3>(u21, 7, 8, 9)' do not work well.
        - 'u3A = Type<UDT3>(Type<UDT2>(1, 2, 3, 4, 5, 6), 7, 8, 9)' and 'Dim As UDT3 u3B = Type<UDT3>(Type<UDT2>(1, 2, 3, 4, 5, 6), 7, 8, 9)' do not work well.
        - 'u3C = Type<UDT3>(Type<UDT2>(Type<UDT1>(1, 2), 3, 4, 5, 6), 7, 8, 9)' and 'Dim As UDT3 u3D = Type<UDT3>(Type<UDT2>(Type<UDT1>(1, 2), 3, 4, 5, 6), 7, 8, 9)' do not work well.
        - 'Dim As UDT4 u41 = UDT4(u31, 10)' does not work well, because 'Base(u31)' is called in UDT4 constructor while 'Cast(UDT3, This) = u31' works well instead.

        Note:
        - 'Dim As UDT3 u32 = (u31)' also does not work well because it is considered as a shortcut of 'Dim As UDT3 u32 = Type<UDT3>(u31)' for an initializer.
        - This is not the case for 'u34 = (u31)' which works well.
      - It seems that the problem is not only linked to calling implicit copy-constructor from derived-type, but rather more generally is the implicit copy/construct in some syntaxes using TYPE() and BASE() (as: 'Type<UDT3>(u31)', 'Type<UDT3>(u21)', 'Type<UDT3>(u21, 7, 8, 9)', 'Type<UDT3>(Type<UDT2>(1, 2, 3, 4, 5, 6), 7, 8, 9)', 'Type<UDT3>(Type<UDT2>(Type<UDT1>(1, 2), 3, 4, 5, 6), 7, 8, 9)', 'UDT4(u31, 10)' because 'Base(u31)' is called in UDT4 copy-constructor).

      - If we uncomment the constructors definitions in UDT3 (inducing explicit copy-constructor definitions), all works well then:
      • Code: Select all

        Type UDT1
            Dim As Integer I11, I12
        End Type
        
        Type UDT2 Extends UDT1
            Dim As Integer I21, I22, I23, I24
        End Type
        
        Type UDT3 Extends UDT2
            Dim As Integer I31, I32, I33
            Declare Constructor()
            Declare Constructor(Byref u3 As UDT3)
            Declare Constructor(Byref u2 As UDT2, Byval i7 As Integer = 0, Byval i8 As Integer = 0, Byval i9 As Integer = 0)
        End Type
        
        Constructor UDT3()
        End Constructor
        
        Constructor UDT3(Byref u3 As UDT3)
            This = u3
        End Constructor
        
        Constructor UDT3(Byref u2 As UDT2, Byval i7 As Integer = 0, Byval i8 As Integer = 0, Byval i9 As Integer = 0)
            Cast(UDT2, This) = u2
            This.I31 = i7 : This.I32 = i8 : This.I33 = i9
        End Constructor
        
        Type UDT4 Extends UDT3
            Dim As Integer I41
            Declare Constructor()
            Declare Constructor(Byref u3 As UDT3, Byval i10 As Integer)
        End Type
        
        Constructor UDT4()
        End Constructor
        
        Constructor UDT4(Byref u3 As UDT3, Byval i10 As Integer)
            Base(u3)
        '    Cast(UDT3, This) = u3
            This.I41 = i10
        End Constructor
        
        Dim As UDT2 u21 = Type<UDT2>(1, 2, 3, 4, 5, 6)
        Print "Dim As UDT2 u21 = Type<UDT2>(1, 2, 3, 4, 5, 6)  => OK"
        Print "  UDT1: "; u21.I11; u21.I12
        Print "  UDT2: "; u21.I21; u21.I22; u21.I23; u21.I24
        Print
        
        Dim As UDT3 u31
        Cast(UDT2, u31) = u21 : u31.I31 = 7 : u31.I32 = 8 : u31.I33 = 9
        Print "Cast(UDT2, u31) = u21 : u31.I31 = 7 : u31.I32 = 8 : u31.I33 = 9  => OK"
        Print "  UDT1: "; u31.I11; u31.I12
        Print "  UDT2: "; u31.I21; u31.I22; u31.I23; u31.I24
        Print "  UDT3: "; u31.I31; u31.I32; u31.I33
        Print
        
        Dim As UDT3 u32 = u31
        Print "Dim As UDT3 u32 = u31  => OK"
        Print "  UDT1: "; u32.I11; u32.I12
        Print "  UDT2: "; u32.I21; u32.I22; u32.I23; u32.I24
        Print "  UDT3: "; u32.I31; u32.I32; u32.I33
        Print
        
        Dim As UDT3 u33 = Type<UDT3>(u31)
        Print "Dim As UDT3 u33 = Type<UDT3>(u31)  => OK"
        Print "  UDT1: "; u33.I11; u33.I12
        Print "  UDT2: "; u33.I21; u33.I22; u33.I23; u33.I24
        Print "  UDT3: "; u33.I31; u33.I32; u33.I33
        Print
        
        Dim As UDT3 u34
        u34 = u31
        Print "u34 = u31  => OK"
        Print "  UDT1: "; u34.I11; u34.I12
        Print "  UDT2: "; u34.I21; u34.I22; u34.I23; u34.I24
        Print "  UDT3: "; u34.I31; u34.I32; u34.I33
        Print
        
        Dim As UDT3 u35
        u35 = Type<UDT3>(u31)
        Print "u35 = Type<UDT3>(u31)  => OK"
        Print "  UDT1: "; u35.I11; u35.I12
        Print "  UDT2: "; u35.I21; u35.I22; u35.I23; u35.I24
        Print "  UDT3: "; u35.I31; u35.I32; u35.I33
        Print
        
        Dim As UDT3 u36
        u36 = Type<UDT3>(u21)
        Print "u36 = Type<UDT3>(u21)  => OK"
        Print "  UDT1: "; u36.I11; u36.I12
        Print "  UDT2: "; u36.I21; u36.I22; u36.I23; u36.I24
        Print "  UDT3: "; u36.I31; u36.I32; u36.I33
        Print
        
        Dim As UDT3 u37 = Type<UDT3>(u21)
        Print "Dim As UDT3 u37 = Type<UDT3>(u21)  => OK"
        Print "  UDT1: "; u37.I11; u37.I12
        Print "  UDT2: "; u37.I21; u37.I22; u37.I23; u37.I24
        Print "  UDT3: "; u37.I31; u37.I32; u37.I33
        Print
        
        Dim As UDT3 u38
        u38 = Type<UDT3>(u21, 7, 8, 9)
        Print "u38 = Type<UDT3>(u21, 7, 8, 9)  => OK"
        Print "  UDT1: "; u38.I11; u38.I12
        Print "  UDT2: "; u38.I21; u38.I22; u38.I23; u38.I24
        Print "  UDT3: "; u38.I31; u38.I32; u38.I33
        Print
        
        Dim As UDT3 u39 = Type<UDT3>(u21, 7, 8, 9)
        Print "Dim As UDT3 u39 = Type<UDT3>(u21, 7, 8, 9)  => OK"
        Print "  UDT1: "; u39.I11; u39.I12
        Print "  UDT2: "; u39.I21; u39.I22; u39.I23; u39.I24
        Print "  UDT3: "; u39.I31; u39.I32; u39.I33
        Print
        
        Dim As UDT3 u3A
        u3A = Type<UDT3>(Type<UDT2>(1, 2, 3, 4, 5, 6), 7, 8, 9)
        Print "u3A = Type<UDT3>(Type<UDT2>(1, 2, 3, 4, 5, 6), 7, 8, 9)  => OK"
        Print "  UDT1: "; u3A.I11; u3A.I12
        Print "  UDT2: "; u3A.I21; u3A.I22; u3A.I23; u3A.I24
        Print "  UDT3: "; u3A.I31; u3A.I32; u3A.I33
        Print
        
        Dim As UDT3 u3B = Type<UDT3>(Type<UDT2>(1, 2, 3, 4, 5, 6), 7, 8, 9)
        Print "Dim As UDT3 u3B = Type<UDT3>(Type<UDT2>(1, 2, 3, 4, 5, 6), 7, 8, 9)  => OK"
        Print "  UDT1: "; u3B.I11; u3B.I12
        Print "  UDT2: "; u3B.I21; u3B.I22; u3B.I23; u3B.I24
        Print "  UDT3: "; u3B.I31; u3B.I32; u3B.I33
        Print
        
        Dim As UDT3 u3C
        u3C = Type<UDT3>(Type<UDT2>(Type<UDT1>(1, 2), 3, 4, 5, 6), 7, 8, 9)
        Print "u3C = Type<UDT3>(Type<UDT2>(Type<UDT1>(1, 2), 3, 4, 5, 6), 7, 8, 9)  => OK"
        Print "  UDT1: "; u3C.I11; u3C.I12
        Print "  UDT2: "; u3C.I21; u3C.I22; u3C.I23; u3C.I24
        Print "  UDT3: "; u3C.I31; u3C.I32; u3C.I33
        Print
        
        Dim As UDT3 u3D = Type<UDT3>(Type<UDT2>(Type<UDT1>(1, 2), 3, 4, 5, 6), 7, 8, 9)
        Print "Dim As UDT3 u3D = Type<UDT3>(Type<UDT2>(Type<UDT1>(1, 2), 3, 4, 5, 6), 7, 8, 9)  => OK"
        Print "  UDT1: "; u3D.I11; u3D.I12
        Print "  UDT2: "; u3D.I21; u3D.I22; u3D.I23; u3D.I24
        Print "  UDT3: "; u3D.I31; u3D.I32; u3D.I33
        Print
        
        Dim As UDT4 u41 =  UDT4(u31, 10)
        Print "Dim As UDT4 u41 =  UDT4(u31, 10)  => Base(u31) in UDT4 constructor  => OK"
        Print "  UDT1: "; u41.I11; u41.I12
        Print "  UDT2: "; u41.I21; u41.I22; u41.I23; u41.I24
        Print "  UDT3: "; u41.I31; u41.I32; u41.I33
        Print "  UDT4: "; u41.I41
        Print
        
        Sleep
        
        • Output:

          Code: Select all

          Dim As UDT2 u21 = Type<UDT2>(1, 2, 3, 4, 5, 6)  => OK
            UDT1:  1 2
            UDT2:  3 4 5 6
          
          Cast(UDT2, u31) = u21 : u31.I31 = 7 : u31.I32 = 8 : u31.I33 = 9  => OK
            UDT1:  1 2
            UDT2:  3 4 5 6
            UDT3:  7 8 9
          
          Dim As UDT3 u32 = u31  => OK
            UDT1:  1 2
            UDT2:  3 4 5 6
            UDT3:  7 8 9
          
          Dim As UDT3 u33 = Type<UDT3>(u31)  => OK
            UDT1:  1 2
            UDT2:  3 4 5 6
            UDT3:  7 8 9
          
          u34 = u31  => OK
            UDT1:  1 2
            UDT2:  3 4 5 6
            UDT3:  7 8 9
          
          u35 = Type<UDT3>(u31)  => OK
            UDT1:  1 2
            UDT2:  3 4 5 6
            UDT3:  7 8 9
          
          u36 = Type<UDT3>(u21)  => OK
            UDT1:  1 2
            UDT2:  3 4 5 6
            UDT3:  0 0 0
          
          Dim As UDT3 u37 = Type<UDT3>(u21)  => OK
            UDT1:  1 2
            UDT2:  3 4 5 6
            UDT3:  0 0 0
          
          u38 = Type<UDT3>(u21, 7, 8, 9)  => OK
            UDT1:  1 2
            UDT2:  3 4 5 6
            UDT3:  7 8 9
          
          Dim As UDT3 u39 = Type<UDT3>(u21, 7, 8, 9)  => OK
            UDT1:  1 2
            UDT2:  3 4 5 6
            UDT3:  7 8 9
          
          u3A = Type<UDT3>(Type<UDT2>(1, 2, 3, 4, 5, 6), 7, 8, 9)  => OK
            UDT1:  1 2
            UDT2:  3 4 5 6
            UDT3:  7 8 9
          
          Dim As UDT3 u3B = Type<UDT3>(Type<UDT2>(1, 2, 3, 4, 5, 6), 7, 8, 9)  => OK
            UDT1:  1 2
            UDT2:  3 4 5 6
            UDT3:  7 8 9
          
          u3C = Type<UDT3>(Type<UDT2>(Type<UDT1>(1, 2), 3, 4, 5, 6), 7, 8, 9)  => OK
            UDT1:  1 2
            UDT2:  3 4 5 6
            UDT3:  7 8 9
          
          Dim As UDT3 u3D = Type<UDT3>(Type<UDT2>(Type<UDT1>(1, 2), 3, 4, 5, 6), 7, 8, 9)  => OK
            UDT1:  1 2
            UDT2:  3 4 5 6
            UDT3:  7 8 9
          
          Dim As UDT4 u41 =  UDT4(u31, 10)  => Base(u31) in UDT4 constructor  => OK
            UDT1:  1 2
            UDT2:  3 4 5 6
            UDT3:  7 8 9
            UDT4:  10
          

Final formulation of the bug:
  • By using TYPE (temporary) or BASE (initializer) keyword applied on a derived type instance, the implicit copy-construct (without explicit copy-constructor definition) only copies the data members of the topmost base of the derived instance (all other data members of the instance are ignored while implicit copy/construct).
    Same behavior with or without explicit destructor defined in UDTs.
    As soon as a corresponding explicit copy-constructor is defined, all works well.

    Detail:
    • - TYPE (temporary) with a simple parameter list of numeric values works well. But Type (temporary) with an UDT instance included in the parameter list or another Type (temporary) nested, both do not work well (without explicit copy-constructor definition).

      - BASE (initializer) calling the implicit copy-constructor of the base does not work well (without explicit copy-constructor definition), but if the implicit copy-assignment operator of the base is called instead (using the CAST keyword to up-cast THIS), this works well then (without explicit copy-assignment operator definition).

I am waiting a bit for possible feedback from Jeff and others before I think about finalizing with a bug report.
fxm
Moderator
Posts: 11420
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Using TYPE() or BASE() on derived instance, implicit copy/construct only copies data members of topmost base

Post by fxm »

fxm wrote: Aug 21, 2022 19:24
Final formulation of the bug:
  • By using TYPE (temporary) or BASE (initializer) keyword applied on a derived type instance, the implicit copy-construct (without explicit copy-constructor definition) only copies the data members of the topmost base of the derived instance (all other data members of the instance are ignored while implicit copy/construct).
    Same behavior with or without explicit destructor defined in UDTs.
    As soon as a corresponding explicit copy-constructor is defined, all works well.

    Detail:
    • - TYPE (temporary) with a simple parameter list of numeric values works well. But Type (temporary) with an UDT instance included in the parameter list or another Type (temporary) nested, both do not work well (without explicit copy-constructor definition).

      - BASE (initializer) calling the implicit copy-constructor of the base does not work well (without explicit copy-constructor definition), but if the implicit copy-assignment operator of the base is called instead (using the CAST keyword to up-cast THIS), this works well then (without explicit copy-assignment operator definition).

I am waiting a bit for possible feedback from Jeff and others before I think about finalizing with a bug report.

Bug report filled in:
#968 Using TYPE() or BASE() on derived instance, implicit copy/construct only copies data members of topmost base
fxm
Moderator
Posts: 11420
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Using TYPE() or BASE() on derived instance, implicit copy/construct only copies data members of topmost base

Post by fxm »

Some syntaxes, that are compatible with one default constructor in the topmost base, work then fine when that default constructor exists explicitly:

- Without default constructor in UDT1:

Code: Select all

Type UDT1
    Dim As Integer I11, I12
End Type

Type UDT2 Extends UDT1
    Dim As Integer I21, I22, I23, I24
End Type

Type UDT3 Extends UDT2
    Dim As Integer I31, I32, I33
End Type

Type UDT4 Extends UDT3
    Dim As Integer I41
    Declare Constructor()
    Declare Constructor(Byref u3 As UDT3, Byval i10 As Integer)
End Type

Constructor UDT4()
End Constructor

Constructor UDT4(Byref u3 As UDT3, Byval i10 As Integer)
    Base(u3)
'    Cast(UDT3, This) = u3
    This.I41 = i10
End Constructor

Dim As UDT1 u11
u11.I11 = 1 : u11.I12 = 2
Print "u11.I11 = 1 : u11.I12 = 2  => OK"
Print "  UDT1: "; u11.I11; u11.I12
Print

Dim As UDT2 u21
Cast(UDT1, u21) = u11 : u21.I21 = 3 : u21.I22 = 4 : u21.I23 = 5 : u21.I24 = 6
Print "Cast(UDT1, u21) = u11 : u21.I21 = 3 : u21.I22 = 4 : u21.I23 = 5 : u21.I24 = 6  => OK"
Print "  UDT1: "; u21.I11; u21.I12
Print "  UDT2: "; u21.I21; u21.I22; u21.I23; u21.I24
Print

Dim As UDT3 u31
Cast(UDT2, u31) = u21 : u31.I31 = 7 : u31.I32 = 8 : u31.I33 = 9
Print "Cast(UDT2, u31) = u21 : u31.I31 = 7 : u31.I32 = 8 : u31.I33 = 9  => OK"
Print "  UDT1: "; u31.I11; u31.I12
Print "  UDT2: "; u31.I21; u31.I22; u31.I23; u31.I24
Print "  UDT3: "; u31.I31; u31.I32; u31.I33
Print

Dim As UDT3 u32 = u31
Print "Dim As UDT3 u32 = u31  => OK"
Print "  UDT1: "; u32.I11; u32.I12
Print "  UDT2: "; u32.I21; u32.I22; u32.I23; u32.I24
Print "  UDT3: "; u32.I31; u32.I32; u32.I33
Print

Dim As UDT3 u33 = Type<UDT3>(u31)
Print "Dim As UDT3 u33 = Type<UDT3>(u31)  => NOK"
Print "  UDT1: "; u33.I11; u33.I12
Print "  UDT2: "; u33.I21; u33.I22; u33.I23; u33.I24
Print "  UDT3: "; u33.I31; u33.I32; u33.I33
Print

Dim As UDT3 u34
u34 = u31
Print "u34 = u31  => OK"
Print "  UDT1: "; u34.I11; u34.I12
Print "  UDT2: "; u34.I21; u34.I22; u34.I23; u34.I24
Print "  UDT3: "; u34.I31; u34.I32; u34.I33
Print

Dim As UDT3 u35
u35 = Type<UDT3>(u31)
Print "u35 = Type<UDT3>(u31)  => NOK"
Print "  UDT1: "; u35.I11; u35.I12
Print "  UDT2: "; u35.I21; u35.I22; u35.I23; u35.I24
Print "  UDT3: "; u35.I31; u35.I32; u35.I33
Print

Dim As UDT4 u41 =  UDT4(u31, 10)
Print "Dim As UDT4 u41 =  UDT4(u31, 10)  => Base(u31) in UDT4 constructor  => NOK"
Print "  UDT1: "; u41.I11; u41.I12
Print "  UDT2: "; u41.I21; u41.I22; u41.I23; u41.I24
Print "  UDT3: "; u41.I31; u41.I32; u41.I33
Print "  UDT4: "; u41.I41
Print

Sleep
  • Code: Select all

    u11.I11 = 1 : u11.I12 = 2  => OK
      UDT1:  1 2
    
    Cast(UDT1, u21) = u11 : u21.I21 = 3 : u21.I22 = 4 : u21.I23 = 5 : u21.I24 = 6  => OK
      UDT1:  1 2
      UDT2:  3 4 5 6
    
    Cast(UDT2, u31) = u21 : u31.I31 = 7 : u31.I32 = 8 : u31.I33 = 9  => OK
      UDT1:  1 2
      UDT2:  3 4 5 6
      UDT3:  7 8 9
    
    Dim As UDT3 u32 = u31  => OK
      UDT1:  1 2
      UDT2:  3 4 5 6
      UDT3:  7 8 9
    
    Dim As UDT3 u33 = Type<UDT3>(u31)  => NOK
      UDT1:  1 2
      UDT2:  0 0 0 0
      UDT3:  0 0 0
    
    u34 = u31  => OK
      UDT1:  1 2
      UDT2:  3 4 5 6
      UDT3:  7 8 9
    
    u35 = Type<UDT3>(u31)  => NOK
      UDT1:  1 2
      UDT2:  0 0 0 0
      UDT3:  0 0 0
    
    Dim As UDT4 u41 =  UDT4(u31, 10)  => Base(u31) in UDT4 constructor  => NOK
      UDT1:  1 2
      UDT2:  0 0 0 0
      UDT3:  0 0 0
      UDT4:  10
    

- With default constructor in UDT1:

Code: Select all

Type UDT1
    Dim As Integer I11, I12
    Declare Constructor()
End Type

Constructor UDT1()
End Constructor

Type UDT2 Extends UDT1
    Dim As Integer I21, I22, I23, I24
End Type

Type UDT3 Extends UDT2
    Dim As Integer I31, I32, I33
End Type

Type UDT4 Extends UDT3
    Dim As Integer I41
    Declare Constructor()
    Declare Constructor(Byref u3 As UDT3, Byval i10 As Integer)
End Type

Constructor UDT4()
End Constructor

Constructor UDT4(Byref u3 As UDT3, Byval i10 As Integer)
    Base(u3)
'    Cast(UDT3, This) = u3
    This.I41 = i10
End Constructor

Dim As UDT1 u11
u11.I11 = 1 : u11.I12 = 2
Print "u11.I11 = 1 : u11.I12 = 2  => OK"
Print "  UDT1: "; u11.I11; u11.I12
Print

Dim As UDT2 u21
Cast(UDT1, u21) = u11 : u21.I21 = 3 : u21.I22 = 4 : u21.I23 = 5 : u21.I24 = 6
Print "Cast(UDT1, u21) = u11 : u21.I21 = 3 : u21.I22 = 4 : u21.I23 = 5 : u21.I24 = 6  => OK"
Print "  UDT1: "; u21.I11; u21.I12
Print "  UDT2: "; u21.I21; u21.I22; u21.I23; u21.I24
Print

Dim As UDT3 u31
Cast(UDT2, u31) = u21 : u31.I31 = 7 : u31.I32 = 8 : u31.I33 = 9
Print "Cast(UDT2, u31) = u21 : u31.I31 = 7 : u31.I32 = 8 : u31.I33 = 9  => OK"
Print "  UDT1: "; u31.I11; u31.I12
Print "  UDT2: "; u31.I21; u31.I22; u31.I23; u31.I24
Print "  UDT3: "; u31.I31; u31.I32; u31.I33
Print

Dim As UDT3 u32 = u31
Print "Dim As UDT3 u32 = u31  => OK"
Print "  UDT1: "; u32.I11; u32.I12
Print "  UDT2: "; u32.I21; u32.I22; u32.I23; u32.I24
Print "  UDT3: "; u32.I31; u32.I32; u32.I33
Print

Dim As UDT3 u33 = Type<UDT3>(u31)
Print "Dim As UDT3 u33 = Type<UDT3>(u31)  => OK"
Print "  UDT1: "; u33.I11; u33.I12
Print "  UDT2: "; u33.I21; u33.I22; u33.I23; u33.I24
Print "  UDT3: "; u33.I31; u33.I32; u33.I33
Print

Dim As UDT3 u34
u34 = u31
Print "u34 = u31  => OK"
Print "  UDT1: "; u34.I11; u34.I12
Print "  UDT2: "; u34.I21; u34.I22; u34.I23; u34.I24
Print "  UDT3: "; u34.I31; u34.I32; u34.I33
Print

Dim As UDT3 u35
u35 = Type<UDT3>(u31)
Print "u35 = Type<UDT3>(u31)  => OK"
Print "  UDT1: "; u35.I11; u35.I12
Print "  UDT2: "; u35.I21; u35.I22; u35.I23; u35.I24
Print "  UDT3: "; u35.I31; u35.I32; u35.I33
Print

Dim As UDT4 u41 =  UDT4(u31, 10)
Print "Dim As UDT4 u41 =  UDT4(u31, 10)  => Base(u31) in UDT4 constructor  => OK"
Print "  UDT1: "; u41.I11; u41.I12
Print "  UDT2: "; u41.I21; u41.I22; u41.I23; u41.I24
Print "  UDT3: "; u41.I31; u41.I32; u41.I33
Print "  UDT4: "; u41.I41
Print

Sleep
  • Code: Select all

    u11.I11 = 1 : u11.I12 = 2  => OK
      UDT1:  1 2
    
    Cast(UDT1, u21) = u11 : u21.I21 = 3 : u21.I22 = 4 : u21.I23 = 5 : u21.I24 = 6  => OK
      UDT1:  1 2
      UDT2:  3 4 5 6
    
    Cast(UDT2, u31) = u21 : u31.I31 = 7 : u31.I32 = 8 : u31.I33 = 9  => OK
      UDT1:  1 2
      UDT2:  3 4 5 6
      UDT3:  7 8 9
    
    Dim As UDT3 u32 = u31  => OK
      UDT1:  1 2
      UDT2:  3 4 5 6
      UDT3:  7 8 9
    
    Dim As UDT3 u33 = Type<UDT3>(u31)  => OK
      UDT1:  1 2
      UDT2:  3 4 5 6
      UDT3:  7 8 9
    
    u34 = u31  => OK
      UDT1:  1 2
      UDT2:  3 4 5 6
      UDT3:  7 8 9
    
    u35 = Type<UDT3>(u31)  => OK
      UDT1:  1 2
      UDT2:  3 4 5 6
      UDT3:  7 8 9
    
    Dim As UDT4 u41 =  UDT4(u31, 10)  => Base(u31) in UDT4 constructor  => OK
      UDT1:  1 2
      UDT2:  3 4 5 6
      UDT3:  7 8 9
      UDT4:  10
    

I think when there is a default constructor (and no copy-constructor), the implicit copy-construct is replaced by a default construct + implicit/explicit assignment (the latter working in all cases).

This default constructor can be explicitly provided by the user (providing an explicit constructor body), or provided by the compiler itself if a data member has an initializer or a data member is a [pseudo] object (object having a default constructor like UDT or var-len string).

Does not work with destructor or/and copy-let operator alone.
fxm
Moderator
Posts: 11420
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Using TYPE() or BASE() on derived instance, implicit copy/construct only copies data members of topmost base

Post by fxm »

coderJeff
Site Admin
Posts: 4017
Joined: Nov 04, 2005 14:23
Location: Ontario, Canada
Contact:

Re: Using TYPE() or BASE() on derived instance, implicit copy/construct only copies data members of topmost base

Post by coderJeff »

fxm wrote: Sep 19, 2022 12:52
fxm, I appreciate the many test cases. Maybe the problem is subtle. First look with one of your earlier tests and it appears that there is a parsing problem; the list of initializers is not mapping correctly on to the UDT's fields. The resulting generated code is setting some fields more than once. After fbc parses a type<udt>(...) form, then internally the next selected field for initialization in the udt hierarchy is wrong. In the generated backend code it's only memory offsets and values so any resemblance to a hierarchy is lost at the low level.

Here is a simplified example with an explanation of what I think might be happening:

Code: Select all

type udt1
    as integer i1, i2
end type

type udt2 extends udt1
    as integer i3, i4, i5
end type

type udt3 extends udt2
    as integer i6, i7, i8, i9
end type

dim as udt3 u

print "u=type<udt3>(type<udt2>(1,2,3,4),6,7,8)"
u=type<udt3>(type<udt2>(1,2,3,4),6,7,8)

print "    udt1: "; u.i1; u.i2
print "    udt2: "; u.i3; u.i4; u.i5
print "    udt3: "; u.i6; u.i7; u.i8; u.i9
OUTPUT:

Code: Select all

'' u=type<udt3>(type<udt2>(1,2,3,4),6,7,8)
''     udt1:  1 2
''     udt2:  6 7 8
''     udt3:  0 0 0 0
''
''  Start initializing at base address of variable
''
''  u.i1 = 1  <--- first "field" of UDT3/UDT2 is UDT1.i1
''  u.i2 = 2       we will accept up to type<UDT2>'s total
''  u.i3 = 3       count of initializers (5 max)
''  u.i4 = 4  <--- last initializer for UDT2 we gave
''  u.i5 = 0  <--- so, pad with zeros to the end of UDT2
''
''  u.i3 = 6  <--- second "field" of UDT3 is start of UDT2
''  u.i4 = 7  <--- and UDT2 accepts 3 initializers
''  u.i5 = 8
''            no more initializers allowed after here
''  u.i6 = 0  <--- pad UDT3 with zeros to the end
''  u.i7 = 0
''  u.i8 = 0
''  u.i9 = 0
fxm
Moderator
Posts: 11420
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Using TYPE() or BASE() on derived instance, implicit copy/construct only copies data members of topmost base

Post by fxm »

coderJeff wrote: Sep 19, 2022 21:12 First look with one of your earlier tests and it appears that there is a parsing problem

But considering my last test case:
fxm wrote: Aug 30, 2022 5:42 Some syntaxes, that are compatible with one default constructor in the topmost base, work then fine when that default constructor exists explicitly:

- Without default constructor in UDT1:

Code: Select all

Type UDT1
    Dim As Integer I11, I12
End Type

Type UDT2 Extends UDT1
    Dim As Integer I21, I22, I23, I24
End Type

Type UDT3 Extends UDT2
    Dim As Integer I31, I32, I33
End Type

Type UDT4 Extends UDT3
    Dim As Integer I41
    Declare Constructor()
    Declare Constructor(Byref u3 As UDT3, Byval i10 As Integer)
End Type

Constructor UDT4()
End Constructor

Constructor UDT4(Byref u3 As UDT3, Byval i10 As Integer)
    Base(u3)
'    Cast(UDT3, This) = u3
    This.I41 = i10
End Constructor

Dim As UDT1 u11
u11.I11 = 1 : u11.I12 = 2
Print "u11.I11 = 1 : u11.I12 = 2  => OK"
Print "  UDT1: "; u11.I11; u11.I12
Print

Dim As UDT2 u21
Cast(UDT1, u21) = u11 : u21.I21 = 3 : u21.I22 = 4 : u21.I23 = 5 : u21.I24 = 6
Print "Cast(UDT1, u21) = u11 : u21.I21 = 3 : u21.I22 = 4 : u21.I23 = 5 : u21.I24 = 6  => OK"
Print "  UDT1: "; u21.I11; u21.I12
Print "  UDT2: "; u21.I21; u21.I22; u21.I23; u21.I24
Print

Dim As UDT3 u31
Cast(UDT2, u31) = u21 : u31.I31 = 7 : u31.I32 = 8 : u31.I33 = 9
Print "Cast(UDT2, u31) = u21 : u31.I31 = 7 : u31.I32 = 8 : u31.I33 = 9  => OK"
Print "  UDT1: "; u31.I11; u31.I12
Print "  UDT2: "; u31.I21; u31.I22; u31.I23; u31.I24
Print "  UDT3: "; u31.I31; u31.I32; u31.I33
Print

Dim As UDT3 u32 = u31
Print "Dim As UDT3 u32 = u31  => OK"
Print "  UDT1: "; u32.I11; u32.I12
Print "  UDT2: "; u32.I21; u32.I22; u32.I23; u32.I24
Print "  UDT3: "; u32.I31; u32.I32; u32.I33
Print

Dim As UDT3 u33 = Type<UDT3>(u31)
Print "Dim As UDT3 u33 = Type<UDT3>(u31)  => NOK"
Print "  UDT1: "; u33.I11; u33.I12
Print "  UDT2: "; u33.I21; u33.I22; u33.I23; u33.I24
Print "  UDT3: "; u33.I31; u33.I32; u33.I33
Print

Dim As UDT3 u34
u34 = u31
Print "u34 = u31  => OK"
Print "  UDT1: "; u34.I11; u34.I12
Print "  UDT2: "; u34.I21; u34.I22; u34.I23; u34.I24
Print "  UDT3: "; u34.I31; u34.I32; u34.I33
Print

Dim As UDT3 u35
u35 = Type<UDT3>(u31)
Print "u35 = Type<UDT3>(u31)  => NOK"
Print "  UDT1: "; u35.I11; u35.I12
Print "  UDT2: "; u35.I21; u35.I22; u35.I23; u35.I24
Print "  UDT3: "; u35.I31; u35.I32; u35.I33
Print

Dim As UDT4 u41 =  UDT4(u31, 10)
Print "Dim As UDT4 u41 =  UDT4(u31, 10)  => Base(u31) in UDT4 constructor  => NOK"
Print "  UDT1: "; u41.I11; u41.I12
Print "  UDT2: "; u41.I21; u41.I22; u41.I23; u41.I24
Print "  UDT3: "; u41.I31; u41.I32; u41.I33
Print "  UDT4: "; u41.I41
Print

Sleep
  • Code: Select all

    u11.I11 = 1 : u11.I12 = 2  => OK
      UDT1:  1 2
    
    Cast(UDT1, u21) = u11 : u21.I21 = 3 : u21.I22 = 4 : u21.I23 = 5 : u21.I24 = 6  => OK
      UDT1:  1 2
      UDT2:  3 4 5 6
    
    Cast(UDT2, u31) = u21 : u31.I31 = 7 : u31.I32 = 8 : u31.I33 = 9  => OK
      UDT1:  1 2
      UDT2:  3 4 5 6
      UDT3:  7 8 9
    
    Dim As UDT3 u32 = u31  => OK
      UDT1:  1 2
      UDT2:  3 4 5 6
      UDT3:  7 8 9
    
    Dim As UDT3 u33 = Type<UDT3>(u31)  => NOK
      UDT1:  1 2
      UDT2:  0 0 0 0
      UDT3:  0 0 0
    
    u34 = u31  => OK
      UDT1:  1 2
      UDT2:  3 4 5 6
      UDT3:  7 8 9
    
    u35 = Type<UDT3>(u31)  => NOK
      UDT1:  1 2
      UDT2:  0 0 0 0
      UDT3:  0 0 0
    
    Dim As UDT4 u41 =  UDT4(u31, 10)  => Base(u31) in UDT4 constructor  => NOK
      UDT1:  1 2
      UDT2:  0 0 0 0
      UDT3:  0 0 0
      UDT4:  10
    

- With default constructor in UDT1:

Code: Select all

Type UDT1
    Dim As Integer I11, I12
    Declare Constructor()
End Type

Constructor UDT1()
End Constructor

Type UDT2 Extends UDT1
    Dim As Integer I21, I22, I23, I24
End Type

Type UDT3 Extends UDT2
    Dim As Integer I31, I32, I33
End Type

Type UDT4 Extends UDT3
    Dim As Integer I41
    Declare Constructor()
    Declare Constructor(Byref u3 As UDT3, Byval i10 As Integer)
End Type

Constructor UDT4()
End Constructor

Constructor UDT4(Byref u3 As UDT3, Byval i10 As Integer)
    Base(u3)
'    Cast(UDT3, This) = u3
    This.I41 = i10
End Constructor

Dim As UDT1 u11
u11.I11 = 1 : u11.I12 = 2
Print "u11.I11 = 1 : u11.I12 = 2  => OK"
Print "  UDT1: "; u11.I11; u11.I12
Print

Dim As UDT2 u21
Cast(UDT1, u21) = u11 : u21.I21 = 3 : u21.I22 = 4 : u21.I23 = 5 : u21.I24 = 6
Print "Cast(UDT1, u21) = u11 : u21.I21 = 3 : u21.I22 = 4 : u21.I23 = 5 : u21.I24 = 6  => OK"
Print "  UDT1: "; u21.I11; u21.I12
Print "  UDT2: "; u21.I21; u21.I22; u21.I23; u21.I24
Print

Dim As UDT3 u31
Cast(UDT2, u31) = u21 : u31.I31 = 7 : u31.I32 = 8 : u31.I33 = 9
Print "Cast(UDT2, u31) = u21 : u31.I31 = 7 : u31.I32 = 8 : u31.I33 = 9  => OK"
Print "  UDT1: "; u31.I11; u31.I12
Print "  UDT2: "; u31.I21; u31.I22; u31.I23; u31.I24
Print "  UDT3: "; u31.I31; u31.I32; u31.I33
Print

Dim As UDT3 u32 = u31
Print "Dim As UDT3 u32 = u31  => OK"
Print "  UDT1: "; u32.I11; u32.I12
Print "  UDT2: "; u32.I21; u32.I22; u32.I23; u32.I24
Print "  UDT3: "; u32.I31; u32.I32; u32.I33
Print

Dim As UDT3 u33 = Type<UDT3>(u31)
Print "Dim As UDT3 u33 = Type<UDT3>(u31)  => OK"
Print "  UDT1: "; u33.I11; u33.I12
Print "  UDT2: "; u33.I21; u33.I22; u33.I23; u33.I24
Print "  UDT3: "; u33.I31; u33.I32; u33.I33
Print

Dim As UDT3 u34
u34 = u31
Print "u34 = u31  => OK"
Print "  UDT1: "; u34.I11; u34.I12
Print "  UDT2: "; u34.I21; u34.I22; u34.I23; u34.I24
Print "  UDT3: "; u34.I31; u34.I32; u34.I33
Print

Dim As UDT3 u35
u35 = Type<UDT3>(u31)
Print "u35 = Type<UDT3>(u31)  => OK"
Print "  UDT1: "; u35.I11; u35.I12
Print "  UDT2: "; u35.I21; u35.I22; u35.I23; u35.I24
Print "  UDT3: "; u35.I31; u35.I32; u35.I33
Print

Dim As UDT4 u41 =  UDT4(u31, 10)
Print "Dim As UDT4 u41 =  UDT4(u31, 10)  => Base(u31) in UDT4 constructor  => OK"
Print "  UDT1: "; u41.I11; u41.I12
Print "  UDT2: "; u41.I21; u41.I22; u41.I23; u41.I24
Print "  UDT3: "; u41.I31; u41.I32; u41.I33
Print "  UDT4: "; u41.I41
Print

Sleep
  • Code: Select all

    u11.I11 = 1 : u11.I12 = 2  => OK
      UDT1:  1 2
    
    Cast(UDT1, u21) = u11 : u21.I21 = 3 : u21.I22 = 4 : u21.I23 = 5 : u21.I24 = 6  => OK
      UDT1:  1 2
      UDT2:  3 4 5 6
    
    Cast(UDT2, u31) = u21 : u31.I31 = 7 : u31.I32 = 8 : u31.I33 = 9  => OK
      UDT1:  1 2
      UDT2:  3 4 5 6
      UDT3:  7 8 9
    
    Dim As UDT3 u32 = u31  => OK
      UDT1:  1 2
      UDT2:  3 4 5 6
      UDT3:  7 8 9
    
    Dim As UDT3 u33 = Type<UDT3>(u31)  => OK
      UDT1:  1 2
      UDT2:  3 4 5 6
      UDT3:  7 8 9
    
    u34 = u31  => OK
      UDT1:  1 2
      UDT2:  3 4 5 6
      UDT3:  7 8 9
    
    u35 = Type<UDT3>(u31)  => OK
      UDT1:  1 2
      UDT2:  3 4 5 6
      UDT3:  7 8 9
    
    Dim As UDT4 u41 =  UDT4(u31, 10)  => Base(u31) in UDT4 constructor  => OK
      UDT1:  1 2
      UDT2:  3 4 5 6
      UDT3:  7 8 9
      UDT4:  10
    

I think when there is a default constructor (and no copy-constructor), the implicit copy-construct is replaced by a default construct + implicit/explicit assignment (the latter working in all cases).

This default constructor can be explicitly provided by the user (providing an explicit constructor body), or provided by the compiler itself if a data member has an initializer or a data member is a [pseudo] object (object having a default constructor like UDT or var-len string).

Does not work with destructor or/and copy-let operator alone.
A parsing problem does not explain:
- the case of 'Base(u31)' in UDT4 constructor (see u41, u31 being ok)
- the fact of the syntaxes 'Dim As UDT3 u33 = Type<UDT3>(u31)', and 'u35 = Type<UDT3>(u31)', (and 'Base(u31)'), works as soon as a UDT1 default constructor exists.
I was thinking more of a problem in the implicit copy-construct (the shallow bit-wise copy).
coderJeff
Site Admin
Posts: 4017
Joined: Nov 04, 2005 14:23
Location: Ontario, Canada
Contact:

Re: Using TYPE() or BASE() on derived instance, implicit copy/construct only copies data members of topmost base

Post by coderJeff »

fxm wrote: Sep 19, 2022 22:08 A parsing problem does not explain:
- the case of 'Base(u31)' in UDT4 constructor (see u41, u31 being ok)
- the fact of the syntaxes 'Dim As UDT3 u33 = Type<UDT3>(u31)', and 'u35 = Type<UDT3>(u31)', (and 'Base(u31)'), works as soon as a UDT1 default constructor exists.
I was thinking more of a problem in the implicit copy-construct (the shallow bit-wise copy).
Ya, it's both implicit a copy-construct problem and parsing problem; they are intimately related.

Under the hood:
- initializers for variables, BASE, NEW, anonymous types, fields, and optional parameters are all handled by a common parser entry point - internally in fbc sources 'cInitializer()
- cInitializer() parsing routine is also the entry point for arrays. Array elements and UDT fields can contain each of the other, so it's a bit of a recursion nightmare to debug.
- the shallow bit-wise copy is generated based on 1) the initializer list given in source by the user, and 2) the UDT's structure as stored in the internal symbol table
- non-trivial types (i.e. having constructor procedures), are handled slightly differently in the parser (i.e. they have a different code path and checks).

This issue was a tricky one, but I've made progress over past week or so. I've added all your test cases to the test-suite and they pass with fbc changes I am working on.
- the major problem I saw was that the parser's handling of the initializer list elements and pairing of the initializers with UDT fields was not correctly synchronized - resulting in bad implicit copy construction.

After I merge the fix, here's what should happen:
- pair the next initializer (in user source) with the next best matched field (in UDT's symbol structure)
- consider every field of the UDT including fields of hidden base types
- initializer elements for TYPE's should pair with and initialize every member of the TYPE sequentially
- initializer elements for UNION's should pair with only the first member of the UNION and skip the rest
- don't implicitly cast parent types to base types; instead pass the initializer back up the parser and try to pair the initializer with a parent type
- different handling (ideally better) of comma and parentheses initializer list delimeters so that next initializer is paired with correct UDT field.

Maybe I will have updates soon. The changes I've made also seem to fix https://sourceforge.net/p/fbc/bugs/894/ for the simple cases given. Though I haven't written any tests for that bug yet.
fxm
Moderator
Posts: 11420
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Using TYPE() or BASE() on derived instance, implicit copy/construct only copies data members of topmost base

Post by fxm »

coderJeff wrote: Sep 25, 2022 17:27 Maybe I will have updates soon. The changes I've made also seem to fix https://sourceforge.net/p/fbc/bugs/894/ for the simple cases given. Though I haven't written any tests for that bug yet.
Thanks for looking into this issue.
fxm
Moderator
Posts: 11420
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Using TYPE() or BASE() on derived instance, implicit copy/construct only copies data members of topmost base

Post by fxm »

I was surprised that the problem was limited to the implicit copy-construct (shallow bit-wise copy) and not the implicit copy-assignment which still works fine.
coderJeff
Site Admin
Posts: 4017
Joined: Nov 04, 2005 14:23
Location: Ontario, Canada
Contact:

Re: Nesting TYPE (temporary) keyword does not support multi-level inheritance structure

Post by coderJeff »

I probably used imprecise terminology to describe concepts. It gets murky under-the-hood because it all starts to look the same at the low-level where we are copying/assigning values from one memory location or immediate value to other memory locations. The problem appeared to be related to certain bit-wise copy/assignment situations.

I think the major difference in technicality where fbc compiler, syntax, and code generation is concerned is 1) if the construct/copy/assignment calls a procedure, or 2) if the construct/copy/assignment is a sequence of bit-wise operations built in-line.

My thoughts/opinions are:
- constructor is a procedure taking 0 or more arguments that assigns values to uninitialized memory. 2 special cases being the default constructor taking 0 arguments and the copy constructor taking exactly 1 argument of the parent type
- assignment operator is a procedure taking exactly 1 argument that assigns values to initialized memory.
- any shallow bit-wise initialization/copy/assignment basically works the same under-the-hood, though conceptually it may be useful to describe it in documentation as an implicit constructor, implicit assignment, etc. However, no procedure is implicitly generated or called.
- then to make matters confusing (of course), we actually have procedures generated implicitly for default constructor, copy constructor, and assignment operator, for fields of built-in types that have fields that require special handling.
fxm
Moderator
Posts: 11420
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Using TYPE() or BASE() on derived instance, implicit copy/construct only copies data members of topmost base

Post by fxm »

coderJeff wrote: Sep 27, 2022 22:41 - any shallow bit-wise initialization/copy/assignment basically works the same under-the-hood, though conceptually it may be useful to describe it in documentation as an implicit constructor, implicit assignment, etc. However, no procedure is implicitly generated or called.
- then to make matters confusing (of course), we actually have procedures generated implicitly for default constructor, copy constructor, and assignment operator, for fields of built-in types that have fields that require special handling.
Indeed, for a non-advanced user, I think there is no point in complicating by differentiating in documentation between bit-wise shallow process (without member code body) and process through internal constructors/let-operator/destructor (added by the compiler when a data member, direct or inherited, has an initializer or is a [pseudo] object).
The 2 things being confused under the term "implicit" process.
Post Reply