Nested Types and Unions

Forum for discussion about the documentation project.
fxm
Moderator
Posts: 12386
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Nested Types and Unions

Post by fxm »

- When a nested type is declared in the private section of the type that nests it, an instance of that nested type can only be created through an instance of the type that nests it.
- So there is a sense in wanting to access members of the type that nests it from that nested type.
- This can be achieved by declaring a dedicated pointer in that nested type and initialized by the constructor of the type that nests it (via the THIS implicit reference).
- Finally, a little sophistication with the code to take advantage of it to validate some capabilities versus this nested structure:

Code: Select all

Type NameType
    Private:
        Dim As String lastName
        Dim As String firstName
        Type AgeType
            Private:
                Dim As Ubyte age
                Dim As NameType Ptr pnt
            Public:
                Declare Operator Cast() As String
                Declare Constructor(Byref t As NameType, Byval age As Ubyte)
        End Type
        Declare Operator Cast() As String
    Public:
        Dim As AgeType Ptr pat
        Declare Constructor(Byref lastName As String, Byref firstName As String, Byval age As Ubyte)
        Declare Destructor()
End Type

Constructor NameType(Byref lastName As String, Byref firstName As String, Byval age As Ubyte)
    This.lastName = lastName
    This.firstName = firstName
    This.pat = New AgeType(This, age)
End Constructor

Destructor NameType()
    Delete This.pat
End destructor

Operator NameType.Cast() As String
    Return "last name: " & This.lastName & ", first name: " & This.firstName
End Operator

Constructor NameType.AgeType(Byref t As NameType, Byval age As Ubyte)
    This.pnt = @t
    This.age = age
End Constructor

Operator NameType.AgeType.Cast() As String
    Return *This.pnt & ", age: " & This.age
End Operator

Dim As NameType t11 = NameType("Miller", "William", 39)
Dim As NameType t12 = NameType("Brown", "John", 47)
Print *t11.pat
Print *t12.pat

Sleep

Code: Select all

last name: Miller, first name: William, age: 39
last name: Brown, first name: John, age: 47
fxm
Moderator
Posts: 12386
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Nested Types and Unions

Post by fxm »

fxm wrote: Nov 02, 2022 22:24 - Finally, a little sophistication with the code to take advantage of it to validate some capabilities versus this nested structure:
And again, I did not push the sophistication to the extreme here above, because I then found thus a bug when I wanted to add a copy-constructor.
See: BUG : Illicit "error 202: Illegal member access, UDT.operator.cast" compiler error message


A patchwork of the bugged compiler error messages for a structure with a Nested Name Type.

With indirect conversions:
- cast() operator + conversion-constructor() matching between them, instead of directly the dedicated constructor(),
- cast() operator + the let() operator matching between them, instead of directly the dedicated let() operator.

Code: Select all

Type TU
    Public:
        Type TV
            Public:
                Dim As String sv
                Declare Constructor()
'            Private:
                Declare Operator Cast() As String
        End Type
        Dim As TV iv
        Declare Constructor()
'        Declare Constructor(Byref v As TV)
        Declare Constructor(Byref s As String)
        Declare Constructor(Byref s As String, Byval n As Integer)
'        Declare Operator Let(Byref v As TV)
        Declare Operator Let(Byref s As String)
        Declare Sub s1(Byval u As TU)
        Declare Function f1() As TU
        Declare Function f2() As TU
End Type

Constructor TU()
    Print "Constructor TU()"
End Constructor

'Constructor TU(Byref v As TV)
'    Print "Constructor TU(Byref As TV)"
'    This.iv.sv = v.sv
'End constructor

Constructor TU(Byref s As String)
    Print "Constructor TU(Byref s As String)"
    This.iv.sv = s
End Constructor

Constructor TU(Byref s As String, Byval n As Integer)
    Print "Constructor TU(Byref As String, Byval As Integer)"
    For I As Integer = 1 To n
        This.iv.sv &= s
    Next I
End constructor

'Operator TU.Let(Byref v As TV)
'    Print "Operator TU.Let(Byref As TV)"
'    This.iv.sv = v.sv
'End Operator

Operator TU.Let(Byref s As String)
    Print "Operator TU.Let(Byref As String)"
    This.iv.sv = s
End Operator

Constructor TU.TV()
    Print "Constructor TV()"
End Constructor

Operator TU.TV.Cast() As String
    Print "Operator TV.Cast() As String"
    Return This.sv
End operator

Sub TU.s1(Byval u As TU)
    This = u
End Sub

Function TU.f1() As TU
    Return This.iv
End function

Function TU.f2() As TU
    Function = This.iv
End function

Dim As TU.TV v
Print

Dim As TU u = v
Print

u = v
Print

u.s1(v)
Print

u.f1()
Print

u.f2()
Print

Sleep

Code: Select all

Constructor TV()

Operator TV.Cast() As String
Constructor TV()
Constructor TU(Byref s As String)

Operator TV.Cast() As String
Operator TU.Let(Byref As String)

Operator TV.Cast() As String
Constructor TV()
Constructor TU(Byref s As String)

Operator TV.Cast() As String
Constructor TV()
Constructor TU(Byref s As String)

Constructor TV()
Constructor TU()
Operator TV.Cast() As String
Operator TU.Let(Byref As String)

If The cast() operator is private -> normal compiler error messages:

Code: Select all

Type TU
    Public:
        Type TV
            Public:
                Dim As String sv
                Declare Constructor()
            Private:
                Declare Operator Cast() As String
        End Type
        Dim As TV iv
        Declare Constructor()
'        Declare Constructor(Byref v As TV)
        Declare Constructor(Byref s As String)
        Declare Constructor(Byref s As String, Byval n As Integer)
'        Declare Operator Let(Byref v As TV)
        Declare Operator Let(Byref s As String)
        Declare Sub s1(Byval u As TU)
        Declare Function f1() As TU
        Declare Function f2() As TU
End Type

Constructor TU()
    Print "Constructor TU()"
End Constructor

'Constructor TU(Byref v As TV)
'    Print "Constructor TU(Byref As TV)"
'    This.iv.sv = v.sv
'End constructor

Constructor TU(Byref s As String)
    Print "Constructor TU(Byref s As String)"
    This.iv.sv = s
End Constructor

Constructor TU(Byref s As String, Byval n As Integer)
    Print "Constructor TU(Byref As String, Byval As Integer)"
    For I As Integer = 1 To n
        This.iv.sv &= s
    Next I
End constructor

'Operator TU.Let(Byref v As TV)
'    Print "Operator TU.Let(Byref As TV)"
'    This.iv.sv = v.sv
'End Operator

Operator TU.Let(Byref s As String)
    Print "Operator TU.Let(Byref As String)"
    This.iv.sv = s
End Operator

Constructor TU.TV()
    Print "Constructor TV()"
End Constructor

Operator TU.TV.Cast() As String
    Print "Operator TV.Cast() As String"
    Return This.sv
End operator

Sub TU.s1(Byval u As TU)
    This = u
End Sub

Function TU.f1() As TU
    Return This.iv
End function

Function TU.f2() As TU
    Function = This.iv
End function

Dim As TU.TV v
Print

Dim As TU u = v
Print

u = v
Print

u.s1(v)
Print

u.f1()
Print

u.f2()
Print

Sleep
C:\.....\FBIDETEMP.bas(67) error 202: Illegal member access, TU.TV.operator.cast in 'Return This.iv'
C:\.....\FBIDETEMP.bas(71) error 202: Illegal member access, TU.TV.operator.cast in 'Function = This.iv'
C:\.....\FBIDETEMP.bas(75) error 202: Illegal member access, TU.TV.operator.cast in 'Dim As TU u = v'
C:\.....\FBIDETEMP.bas(78) error 202: Illegal member access, TU.TV.operator.cast in 'u = v'
C:\.....\FBIDETEMP.bas(81) error 202: Illegal member access, TU.TV.operator.cast at parameter 1 (u) of S1() in 'u.s1(v)'

With direct assignment added to the existing code:
+ dedicated constructor(),
+ dedicated let() operator.
=> cast() operator no longer called.

Code: Select all

Type TU
    Public:
        Type TV
            Public:
                Dim As String sv
                Declare Constructor()
'            Private:
                Declare Operator Cast() As String
        End Type
        Dim As TV iv
        Declare Constructor()
        Declare Constructor(Byref v As TV)
        Declare Constructor(Byref s As String)
        Declare Constructor(Byref s As String, Byval n As Integer)
        Declare Operator Let(Byref v As TV)
        Declare Operator Let(Byref s As String)
        Declare Sub s1(Byval u As TU)
        Declare Function f1() As TU
        Declare Function f2() As TU
End Type

Constructor TU()
    Print "Constructor TU()"
End Constructor

Constructor TU(Byref v As TV)
    Print "Constructor TU(Byref As TV)"
    This.iv.sv = v.sv
End constructor

Constructor TU(Byref s As String)
    Print "Constructor TU(Byref s As String)"
    This.iv.sv = s
End Constructor

Constructor TU(Byref s As String, Byval n As Integer)
    Print "Constructor TU(Byref As String, Byval As Integer)"
    For I As Integer = 1 To n
        This.iv.sv &= s
    Next I
End constructor

Operator TU.Let(Byref v As TV)
    Print "Operator TU.Let(Byref As TV)"
    This.iv.sv = v.sv
End Operator

Operator TU.Let(Byref s As String)
    Print "Operator TU.Let(Byref As String)"
    This.iv.sv = s
End Operator

Constructor TU.TV()
    Print "Constructor TV()"
End Constructor

Operator TU.TV.Cast() As String
    Print "Operator TV.Cast() As String"
    Return This.sv
End operator

Sub TU.s1(Byval u As TU)
    This = u
End Sub

Function TU.f1() As TU
    Return This.iv
End function

Function TU.f2() As TU
    Function = This.iv
End function

Dim As TU.TV v
Print

Dim As TU u = v
Print

u = v
Print

u.s1(v)
Print

u.f1()
Print

u.f2()
Print

Sleep

Code: Select all

Constructor TV()

Constructor TV()
Constructor TU(Byref As TV)

Operator TU.Let(Byref As TV)

Constructor TV()
Constructor TU(Byref As TV)

Constructor TV()
Constructor TU(Byref As TV)

Constructor TV()
Constructor TU()
Operator TU.Let(Byref As TV)

But with the cast() operator declared private, illicit compiler error messages are obtained:

Code: Select all

Type TU
    Public:
        Type TV
            Public:
                Dim As String sv
                Declare Constructor()
            Private:
                Declare Operator Cast() As String
        End Type
        Dim As TV iv
        Declare Constructor()
        Declare Constructor(Byref v As TV)
        Declare Constructor(Byref s As String)
        Declare Constructor(Byref s As String, Byval n As Integer)
        Declare Operator Let(Byref v As TV)
        Declare Operator Let(Byref s As String)
        Declare Sub s1(Byval u As TU)
        Declare Function f1() As TU
        Declare Function f2() As TU
End Type

Constructor TU()
    Print "Constructor TU()"
End Constructor

Constructor TU(Byref v As TV)
    Print "Constructor TU(Byref As TV)"
    This.iv.sv = v.sv
End constructor

Constructor TU(Byref s As String)
    Print "Constructor TU(Byref s As String)"
    This.iv.sv = s
End Constructor

Constructor TU(Byref s As String, Byval n As Integer)
    Print "Constructor TU(Byref As String, Byval As Integer)"
    For I As Integer = 1 To n
        This.iv.sv &= s
    Next I
End constructor

Operator TU.Let(Byref v As TV)
    Print "Operator TU.Let(Byref As TV)"
    This.iv.sv = v.sv
End Operator

Operator TU.Let(Byref s As String)
    Print "Operator TU.Let(Byref As String)"
    This.iv.sv = s
End Operator

Constructor TU.TV()
    Print "Constructor TV()"
End Constructor

Operator TU.TV.Cast() As String
    Print "Operator TV.Cast() As String"
    Return This.sv
End operator

Sub TU.s1(Byval u As TU)
    This = u
End Sub

Function TU.f1() As TU
    Return This.iv
End function

Function TU.f2() As TU
    Function = This.iv
End function

Dim As TU.TV v
Print

Dim As TU u = v
Print

u = v
Print

u.s1(v)
Print

u.f1()
Print

u.f2()
Print

Sleep
C:\.....\FBIDETEMP.bas(67) error 202: Illegal member access, TU.TV.operator.cast in 'Return This.iv'
C:\.....\FBIDETEMP.bas(71) error 202: Illegal member access, TU.TV.operator.cast in 'Function = This.iv'
C:\.....\FBIDETEMP.bas(75) error 202: Illegal member access, TU.TV.operator.cast in 'Dim As TU u = v'
C:\.....\FBIDETEMP.bas(78) error 202: Illegal member access, TU.TV.operator.cast in 'u = v'
C:\.....\FBIDETEMP.bas(81) error 202: Illegal member access, TU.TV.operator.cast at parameter 1 (u) of S1() in 'u.s1(v)'
fxm
Moderator
Posts: 12386
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Nested Types and Unions

Post by fxm »

Incomplete type versus forward referencing

If a member procedure declares byval parameters (or byval function return) referring to its own Type, there are updates after full UDT parsing:

Code: Select all

Type UDT1
    Declare Sub test(Byval t1 As UDT1)
    Dim As String s
    Dim As Integer i
End Type

Sub UDT1.test(Byval t1 As UDT1)
    Print t1.s
    Print t1.i
End Sub

Dim As UDT1 t10

Dim As UDT1 t11
t11.s = "Free"
t11.i = 1234

t10.test(t11)

Sleep

Code: Select all

Free
 1234
 

But this member procedure capability does not work for forward referencing, even referring to its own Type, which is equivalent to the previous case ???

Code: Select all

Type _UDT1 As UDT1

Type UDT1
    Declare Sub test(Byval t1 As _UDT1)
    Dim As String s
    Dim As Integer i
End Type

Sub UDT1.test(Byval t1 As UDT1)
    Print t1.s
    Print t1.i
End Sub

Dim As UDT1 t10

Dim As UDT1 t11
t11.s = "Free"
t11.i = 1234

t10.test(t11)

Sleep
C:\.....\FBIDETEMP.bas(4) error 71: Incomplete type, before ')' in 'Declare Sub test(Byval t1 As _UDT1)'

Example working for 'Byval As UDT1', but not for 'Byval As _UDT0' (there, forward referencing is for another Type further):

Code: Select all

Type _UDT0 As UDT0

Type UDT1
    Declare Sub test(Byval t1 As UDT1, Byval t0 As _UDT0)
    Dim As String s
    Dim As Integer i
End Type

Type UDT0
    Dim As UDT1 u1
End Type

Sub UDT1.test(Byval t1 As UDT1, Byval t0 As UDT0)
    Print t1.s
    Print t1.i
    Print t0.u1.s
    Print t0.u1.i
End Sub

Dim As UDT1 t10
Dim As UDT0 t00

Dim As UDT1 t11
t11.s = "Free"
t11.i = 1234

Dim As UDT0 t01
t01.u1.s = "BASIC"
t01.u1.i = 5678

t10.test(t11, t01)
t00.u1.test(t11, t01)

Sleep
C:\.....\FBIDETEMP.bas(4) error 71: Incomplete type, before ')' in 'Declare Sub test(Byval t1 As UDT1, Byval t0 As _UDT0)'

The same code, with just using a Nested Named Type to eliminate the forward referencing, solves the problem and works for both 'Byval As UDT1' and 'Byval As UDT0':

Code: Select all

Type UDT0
    Type UDT1
        Declare Sub test(Byval t1 As UDT1, Byval t0 As UDT0)
        Dim As String s
        Dim As Integer i
    End Type
    Dim As UDT1 u1
End Type

Sub UDT0.UDT1.test(Byval t1 As UDT1, Byval t0 As UDT0)
    Print t1.s
    Print t1.i
    Print t0.u1.s
    Print t0.u1.i
End Sub

Dim As UDT0.UDT1 t10
Dim As UDT0 t00

Dim As UDT0.UDT1 t11
t11.s = "Free"
t11.i = 1234

Dim As UDT0 t01
t01.u1.s = "BASIC"
t01.u1.i = 5678

t10.test(t11, t01)
t00.u1.test(t11, t01)

Sleep

Code: Select all

Free
 1234
BASIC
 5678
Free
 1234
BASIC
 5678
 
fxm
Moderator
Posts: 12386
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Nested Types and Unions

Post by fxm »

fxm wrote: Oct 29, 2022 7:48
'Type (UDT/Alias/Temporary) and Union' Programmer's Guide page wrote:
Contents (to highlight)

Type (UDT):
  • Named Type: => Declare a named trivial/complex Type structure, that can be nested inside another named Type/Union structure.
  • Anonymous Type: => Define an inner unnamed trivial Type structure nested inside another named or unnamed Union structure.
Type (Alias): => Declare an alternative name for a named Type.

Type (Temporary): => Create a temporary instance of a named Type.

Union:
  • Named Union: => Declare a named trivial/complex Union structure, that can be nested inside another named Type/Union structure.
  • Anonymous Union: => Define an inner unnamed trivial Union structure nested inside another named or unnamed Type structure.
(*)
Type/Union structure versus scope location:
  • Trivial structure: => Named or Unnamed Type/Union that can be located in both global or local scope.
  • Complex structure: => Named Type/Union that can only be located in a global scope.
  • Extended structure: => Named Type/Union in a scope that has visibility to its Base's scope (currently in same scope than its Base).
(*) added according to posts below

This documentation page is now available (in first full version) in the Programmer's Guide (User Defined Types):
Type (UDT/Alias/Temporary) and Union
fxm
Moderator
Posts: 12386
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Nested Types and Unions

Post by fxm »

@Jeff,

From the 'error 21: Internal!, HMEMBERID' topic:
fxm wrote: Nov 16, 2022 12:03
CanMetax wrote: Nov 16, 2022 10:24 Hello,

Code: Select all

enum colors
		RED= 1
		GREEN
		BLUE
end enum

type _colors as colors

type foo

	type farbe as _colors

private:
	as ubyte nop= -1
end type

dim as foo bar
bar.farbe= GREEN


With the last freeBASIC compiler version (under testing) which allows the Nested Types (I suppose you use it), this declaration ('type farbe as _colors') is a Type (Alias) declaration nested in the 'foo' Type (UDT), which is valid.
Your code is valid up to:
'bar.farbe= GREEN'
Here, I think this detected internal error is not the one to report to user and must be modified.

Simple example of bugged error message:

Code: Select all

Type UDT
    Dim As Integer I
    Type Int_ As Long
End Type

Dim As UDT u
u.Int_ = 0
C:\.....\FBIDETEMP.bas(7) error 21: Internal!, HMEMBERID in 'u.Int_ = 0'
fxm
Moderator
Posts: 12386
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Nested Types and Unions

Post by fxm »

According to two previous posts (viewtopic.php?p=295444#p295444 and viewtopic.php?p=295446#p295446), I filled in a bug report on inheritance with Types in different scopes, not necessarily for Nested Type(s):
#972 A local Type cannot access members of an inherited Type external to its scope but normally accessible
fxm
Moderator
Posts: 12386
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Nested Types and Unions

Post by fxm »

BUG: Private nested UDT in base Type should not be accessible from declaration zone of derived Type.
(But no BUG: Private nested UDT in base Type is not accessible from procedure body of derived Type)

Example with private/protected/public members inside a base Type:
- with nested UDTs, (NOK)
- with static integers, (OK)
referred from a derived Type:
- from declaration zone, (NOK)
- from procedure body, (OK)
and also referred from the main code. (OK)

Code: Select all

Type Parent
    Dim As Integer __
    Private:
        Static As Integer IP1
        Type UDTP1
            Dim As Integer __
        End Type
    Protected:
        Static As Integer IP2
        Type UDTP2
            Dim As Integer __
        End Type
    Public:
        Static As Integer IP3
        Type UDTP3
            Dim As Integer __
        End Type
End Type
Dim As Integer Parent.IP1
Dim As Integer Parent.IP2
Dim As Integer Parent.IP3

Type Child Extends Parent
    Dim As UDTP1 UC1          '' No error: NOK, should be error: 'Illegal member access'  ***** BUG *****
    Dim As UDTP2 UC2          '' No error: OK
    Dim As UDTP3 UC3          '' No error: OK
    Dim As Integer IC1 = IP1  '' error OK: 'Illegal member access'
    Dim As Integer IC2 = IP2  '' No error: OK
    Dim As Integer IC3 = IP3  '' No error: OK
    Declare Constructor()
End Type

Constructor Child()
    Dim As UDTP1 UC1          '' error OK: 'Illegal member access'
    Dim As UDTP2 UC2          '' No error: OK
    Dim As UDTP3 UC3          '' No error: OK
    Dim As Integer IC1 = IP1  '' error OK: 'Illegal member access'
    Dim As Integer IC2 = IP2  '' No error: OK
    Dim As Integer IC3 = IP3  '' No error: OK
End Constructor

Dim As Parent.UDTP1 UC1          '' error OK: 'Illegal member access'
Dim As Parent.UDTP2 UC2          '' error OK: 'Illegal member access'
Dim As Parent.UDTP3 UC3          '' No error: OK
Dim As Integer IC1 = Parent.IP1  '' error OK: 'Illegal member access'
Dim As Integer IC2 = Parent.IP2  '' error OK: 'Illegal member access'
Dim As Integer IC3 = Parent.IP3  '' No error: OK
See the line corresponding to the '..... ***** BUG *****' comment.
(this line should normally trigger a compile error)
Last edited by fxm on Oct 04, 2024 11:06, edited 1 time in total.
dodicat
Posts: 8166
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: Nested Types and Unions

Post by dodicat »

Where is the parent bit of this?
and
UDTP1
UDTP2
UDTP3
are not defined anywhere.
You did say (Example), and not part of an Example.
fxm
Moderator
Posts: 12386
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Nested Types and Unions

Post by fxm »

Thanks dodicat, a piece of code was skipped in my post above.
I just fixed my post above with the correct code.
fxm
Moderator
Posts: 12386
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Nested Types and Unions

Post by fxm »

fxm wrote: Oct 02, 2024 20:05 BUG: Private nested UDT in base Type should not be accessible from declaration zone of derived Type.
(But no BUG: Private nested UDT in base Type is not accessible from procedure body of derived Type)

Bug report filled in:
1007 Private nested UDT in base Type should not be accessible from declaration zone of derived Type
Post Reply