Nested Types and Unions

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

Re: Nested Types and Unions

Post by fxm »

When there are circular dependencies between types, Nested Named Type usage can avoid using type aliases and forward referencing:
- Simple example of two dependent types, with a type alias and a forward referencing:

Code: Select all

Type list As list_

Type listnode
    text As String
    parent As list Ptr
End Type

Type list_
    first As listnode Ptr
    count As Integer
End Type
- Simple example of two dependent types, with simply one of them a Nested Named Type:

Code: Select all

Type list
    count As Integer
    Type listnode
        text As String
        parent As list Ptr
    End Type
    first As listnode Ptr
End Type
fxm
Moderator
Posts: 12081
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Nested Types and Unions

Post by fxm »

Problem to define a static member variable declared in a private Nested Named Type

Testing without the last change, there is no possibility to define such a static variable:
- neither outside the outer type,
- nor outside the inner type (but inside the outer type).

Can the last change allow such a definition and how ?

Simple code example:

Code: Select all

Type T1
    Dim As Integer I1
    Private:
        Static As Integer SI1
        Type T2
            Static As Integer SI2
            Dim As Integer I2
        End Type
        Dim As Integer T2.SI2  '' Duplicated definition, T2
End Type

Dim As Integer T1.SI1
Dim As Integer T1.T2.SI2  '' Illegal member access, found T2


[edit]
OK now, after the changes.
Last edited by fxm on Oct 26, 2022 4:57, edited 1 time in total.
Reason: Update after fbc changes.
coderJeff
Site Admin
Posts: 4313
Joined: Nov 04, 2005 14:23
Location: Ontario, Canada
Contact:

Re: Nested Types and Unions

Post by coderJeff »

fxm wrote: Oct 22, 2022 18:15 Can the last change allow such a definition and how ?
Thanks for the test. Last change to fbc/master won't allow it. But it's an easy fix.

I am missing a flag in parsing of the variable declaration that will allow 'Dim As Integer T1.T2.SI2' to define a static member even if private.
It's the same flag that allows definition of private procedures. For example even if `declare sub proc` were private, `sub T1.T2.proc() ...` is still allowed for definition.

Currently,
- complete tests in the test-suite are lacking
- visibility checks need quite a bit of work
- nested Typedefs (TYPE <name> as <datatype>) don't support visibility attributes.
- probably need to revisit of ENUM access in the future
- accessing deeply nested named type fields from within deeply nested named type procedures not tested - I started writing tests for visibility and was overwhelmed by the permutations of nested members.

Anyway, I am glad you are helping with the testing.
fxm
Moderator
Posts: 12081
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Nested Types and Unions

Post by fxm »

Existing documentation pages updated:
- KeyPgType → fxm [added Nested Type-Def]
- KeyPgUnion → fxm [added Nested Type-Def]
Last edited by fxm on Oct 28, 2022 13:58, edited 1 time in total.
coderJeff
Site Admin
Posts: 4313
Joined: Nov 04, 2005 14:23
Location: Ontario, Canada
Contact:

Re: Nested Types and Unions

Post by coderJeff »

- Difference from anonymous inner types

Anonymous Type (or union):
- does not have a name and cannot be referenced by name
- may only appear nested within a named type or another anonymous type
- declares fields within the parent - either at separate memory locations (TYPE) or overlapping memory locations (UNION)
- cannot contain any static members or procedures declarations
- fields can be referenced

Code: Select all

type T
	union
		dim a as short
		type
			dim b1 as byte
			dim b2 as byte
		end type
	end union
    declare sub proc()
end type

sub T.proc()
	b1 = 1
	b2 = 2
	print b1, b2, a
end sub

dim x as T
x.proc()
Named Type (or union):
- has a name that can be referenced to declare the data type for fields, variables, parameters, arrays, etc.
- can appear on it's own or nested inside another NamedType
- declaration of the type (or union) only
- does not declare any fields within the parent, so it does not add any size to the parent

Code: Select all

type T
	union U
		a as short
		type  '' anonymous
			b1 as byte
			b2 as byte
		end type
		declare sub proc()
	end union
	dim m as U	
    declare sub proc()
end type

sub T.proc()
	m.b1 = 1
	m.b2 = 2
	print m.b1, m.b2, m.a 
end sub

sub T.U.proc()
	print b1, b2, a
end sub

dim x as T
x.proc()
x.m.proc()
fxm
Moderator
Posts: 12081
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Nested Types and Unions

Post by fxm »

Testing Visibility for Nested Type-Def's versus access atributes

Visibility is OK, but some private access configurations induce a general error message ('error 17: Syntax error') instead of the dedicated error message ('error 202: Illegal member access'):

Code: Select all

Type T1
    Public:
        Type A1 As T1
        Type T21
            Public:
                Type A2 As T1
                Type A3 As T21
            Private:
                Type A4 As T1
                Type A5 As T21
                Dim As Integer __
        End Type
        Type A6 As T21
    Private:
        Type A7 As T1
        Type T22
            Public:
                Type A8  As T1
                Type A9  As T21
                Type A10 As T22
            Private:
                Type A11 As T1
                Type A12 As T21
                Type A13 As T22
                Dim As Integer __
        End Type
        Type A14 As T21
        Type A15 As T22
        Dim As Integer __
End Type

Dim As T1 i0
Dim As T1.A1 i1
Dim As T1.T21.A2  i2
Dim As T1.T21.A3  i3
Dim As T1.T21.A4  i4   '' error 17: Syntax error             <== ?
Dim As T1.T21.A5  i5   '' error 17: Syntax error             <== ?
Dim As T1.A6      i6
Dim As T1.A7      i7   '' error 17: Syntax error             <== ?
Dim As T1.T22.A8  i8   '' error 202: Illegal member access
Dim As T1.T22.A9  i9   '' error 202: Illegal member access
Dim As T1.T22.A10 i10  '' error 202: Illegal member access
Dim As T1.T22.A11 i11  '' error 202: Illegal member access
Dim As T1.T22.A12 i12  '' error 202: Illegal member access
Dim As T1.T22.A13 i13  '' error 202: Illegal member access
Dim As T1.A14     i14  '' error 17: Syntax error             <== ?
Dim As T1.A15     i15  '' error 202: Illegal member access


[edit]
OK now, after the change.
Last edited by fxm on Oct 26, 2022 8:56, edited 1 time in total.
Reason: Update after fbc change.
fxm
Moderator
Posts: 12081
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Nested Types and Unions

Post by fxm »

coderJeff wrote: Oct 16, 2022 21:18 Mostly everything you can do in a named TYPE|UNION can also be done in a nested named TYPE|UNION.
Regarding your sentence above, so far I can not find any valid functionality on a Non-Nested Named Type that does not also work on a Nested Named Type.
This includes using 'Extends Other_Type / Object' (with virtuality and polymorphism) on Nested Named Types.
Besides, I don't see why it would be otherwise (except for a malfunction that we would decide not to correct).

A Nested Named Type can be simply thought of as a normal Named Type, but as if it were defined in the namespace of the types that nest it when declared.
Example highlighting it:

Code: Select all

Type UDT1 field = 1
    Dim As Longint __
    Dim As Byte i1
    Type UDT2 field = 1
        Dim As Longint __
        Dim As Longint ___
        Dim As Short i2
        Type UDT3 field = 1
            Dim As Longint __
            Dim As Longint ___
            Dim As Longint ____
            Dim As Long i3
        End Type
    End Type
End Type

Print Sizeof(UDT1)
Print Sizeof(UDT1.UDT2)
Print Sizeof(UDT1.UDT2.UDT3)
Print
Print Sizeof(UDT1.i1)
Print Sizeof(UDT1.UDT2.i2)
Print Sizeof(UDT1.UDT2.UDT3.i3)
Print
Print Offsetof(UDT1, i1)
Print Offsetof(UDT1.UDT2, i2)
Print Offsetof(UDT1.UDT2.UDT3, i3)
Print
9
18
28

1
2
4

8
16
24
coderJeff
Site Admin
Posts: 4313
Joined: Nov 04, 2005 14:23
Location: Ontario, Canada
Contact:

Re: Nested Types and Unions

Post by coderJeff »

fxm wrote: Oct 26, 2022 13:18
coderJeff wrote: Oct 16, 2022 21:18 Mostly everything you can do in a named TYPE|UNION can also be done in a nested named TYPE|UNION.
Regarding your sentence above, so far I can not find any valid functionality on a Non-Nested Named Type that does not also work on a Nested Named Type.
I was beginning to have this thought too. For the documentation, instead of a special page for "nested types", KeyPgType could possibly be a disambiguation page only for "named type", "type (alias)", "anonymous type", "temporary type", etc, for whatever variants of the "type" keyword are used.

To be honest when I wrote that sentence I was thinking of the bug #649 field initializers/member proc decls see inconsistent UDT state - which is more a limitation of the current parser design than what could or should be allowed.

So far, I have only found issues with default initializers where the nested type depends on some property of the parent type - they either crash the compiler or generate bad code. And is related to the bug above, and would require some major internal rewrites to solve.

Also, I have been expecting to find some issue with implementation of nested type default members (constructor/assignment/etc) where the nested type depends on full declaration of the parent type. However, I didn't find a test case yet that results in error or crashes.
fxm
Moderator
Posts: 12081
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Nested Types and Unions

Post by fxm »

fxm wrote: Oct 26, 2022 13:18
coderJeff wrote: Oct 16, 2022 21:18 Mostly everything you can do in a named TYPE|UNION can also be done in a nested named TYPE|UNION.
Regarding your sentence above, so far I can not find any valid functionality on a Non-Nested Named Type that does not also work on a Nested Named Type.
This includes using 'Extends Other_Type / Object' (with virtuality and polymorphism) on Nested Named Types.
Besides, I don't see why it would be otherwise (except for a malfunction that we would decide not to correct).
coderJeff wrote: Oct 27, 2022 21:26 To be honest when I wrote that sentence I was thinking of the bug #649 field initializers/member proc decls see inconsistent UDT state - which is more a limitation of the current parser design than what could or should be allowed.

Indeed, the fact of nesting a Type in another can make appear, seen from the nested Type, an incomplete declaration of the Type configuration which nests it.
Compared to a serial structure, an equivalent but nested structure can lead (except for Type pointers) either to a different behavior (malfunction) or to a compile-time error:
  • Example 1:

    Code: Select all

    Type T1
        Dim As Longint I1
    End Type
    
    Type T2
        Dim As Integer I2 = Sizeof(T1)
    End Type
        
    Dim As T2 t
    Print t.I2      '' 8
    

    Code: Select all

    Type T1
        Type T2
            Dim As Integer I2 = Sizeof(T1)
        End Type
        Dim As Longint I1
    End Type
    
    Dim As T1.T2 t
    Print t.I2      '' 0
    
    Example 2:

    Code: Select all

    Type T1
        Dim As Longint I
    End Type
    
    Type T2
        Dim As T1 t  '' OK
    End Type
    

    Code: Select all

    Type T1
        Type T2
            Dim As T1 t  '' error 24: Invalid data types
        End Type
        Dim As Longint I
    End Type
    
    Example 3

    Code: Select all

    Type T1
        Dim As Longint I1
    End Type
    
    Type T2 Extends T1    '' OK
        Dim As Longint I2
    End Type
    

    Code: Select all

    Type T1
        Type T2 Extends T1    '' error 24: Invalid data types
            Dim As Longint I2
        End Type
        Dim As Longint I1
    End Type
    

Such defects introduced by nesting could be part of what I have called defects that we decide not to fix.
Because a similar incomplete Type configuration has indeed been fixed in the case of static member variables that use as Type the one that contains their declarations.
Such static member variables have to be updated (i.e. their size must be recalculated) after the Type was fully parsed:

Code: Select all

Type UDT
    Static As UDT u
    Dim As Longint I
    Dim As Longint J
End Type

Print Sizeof(UDT.u)  '' 16
fxm
Moderator
Posts: 12081
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Nested Types and Unions

Post by fxm »

1)
Added 'Nested Named Type/Union' example to both documentation pages:
- KeyPgType → fxm [added example with Nested Named Type]
- KeyPgUnion → fxm [added example with Nested Named Union]

2)
coderJeff wrote: Oct 27, 2022 21:26 For the documentation, instead of a special page for "nested types", KeyPgType could possibly be a disambiguation page only for "named type", "type (alias)", "anonymous type", "temporary type", etc, for whatever variants of the "type" keyword are used
I would rather see this new "disambiguation" page ('Type' keywords) in the Programmer's Guide, as I did previously with the New and Delete page.
coderJeff
Site Admin
Posts: 4313
Joined: Nov 04, 2005 14:23
Location: Ontario, Canada
Contact:

Re: Nested Types and Unions

Post by coderJeff »

fxm wrote: Oct 28, 2022 6:44 I would rather see this new "disambiguation" page ('Type' keywords) in the Programmer's Guide, as I did previously with the New and Delete page.
Ah yes, that makes sense. I was worried that KeyPgType would be seen as too verbose for a new user, but it also highlights the the syntax for trivial types at the top of the page.
fxm
Moderator
Posts: 12081
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Nested Types and Unions

Post by fxm »

coderJeff wrote: Oct 27, 2022 21:26 For the documentation, instead of a special page for "nested types", KeyPgType could possibly be a disambiguation page only for "named type", "type (alias)", "anonymous type", "temporary type", etc, for whatever variants of the "type" keyword are used

What is 'etc' (besides what is mentioned below) ?
'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
Last edited by fxm on Oct 30, 2022 9:04, edited 20 times in total.
Reason: Updated according to posts below.
coderJeff
Site Admin
Posts: 4313
Joined: Nov 04, 2005 14:23
Location: Ontario, Canada
Contact:

Re: Nested Types and Unions

Post by coderJeff »

fxm wrote: Oct 29, 2022 7:48 What is 'etc' (besides what is mentioned below) ?
I'm not sure if we would call it variations on the use of TYPE keyword, but there's a few terms that seem to come up in discussions on the forums:
- Trivial types, which have no member procedures and can be declared at global / namespace / nested scopes or inside local scopes (like SCOPE or SUB).
- Complex types, which have constructors / member procedures that must be declared at the global / namespace / nested scope with definitions at the global / namespace scope
- Extended types, which must be based on a named type and follows scoping rules of the base type (trivial or complex).
fxm
Moderator
Posts: 12081
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Nested Types and Unions

Post by fxm »

Yes I see.

But if a local Type is declared to inherit from a global Type, the compilation error does not appear on the 'Extends' keyword of the local Type (and size of the local Type includes the inherited fields), but only if we try to access the fields of its Base:

Code: Select all

Type Parent
    Dim As Longint I
End Type

Sub test()
    Type Child Extends Parent  '' OK
        Dim As Longint J
    End Type
    
    Print Sizeof(Child)  '' Ok: 2 Longint
    Dim As Child c
'    c.I = 123  '' error 18: Element not defined, I
    c.J = 456
'    Print c.I '' error 18: Element not defined, I
    Print c.J
End Sub

test()

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

Re: Nested Types and Unions

Post by coderJeff »

fxm wrote: Oct 29, 2022 12:35 But if a local Type is declared to inherit from a global Type, the compilation error does not appear on the 'Extends' keyword of the local Type (and size of the local Type includes the inherited fields), but only if we try to access the fields of its Base:
That looks like a bug, and not related to recent changes.
Under the hood, 'scope' is a just integer indicating the depth of scope where 'scope(child) := scope(parent) + 1'

Currently, the check is something like this:
if( scope(parent) = scope(child) ) then check parent

But maybe should be:
if( scope(parent) <= scope(child) ) then check parent

It seems like we should allow:

Code: Select all

scope
  type T1
    a as integer
  end type
  scope
    type T2 extends T1
      b as integer
    end type
    scope
      type T3 extends T2
        c as integer
      end type
      dim x as T3 = (1,2,3)
      print x.a
      print x.b
      print x.c
    end scope
  end scope
end scope
But of course is not so simple under the hood. By extension we should also expect to be able to do:

Code: Select all

namespace N
  type T1
    a as integer
  end type
end namespace

scope
  using N
  type T2 extends T1
    b as integer
  end type
  scope
    type T3 extends T2
      c as integer
    end type
    dim x as T3 = (1,2,3)
    print x.a
    print x.b
    print x.c
  end scope
end scope
But internally in fbc, it's not a simple of a comparison of scope depth due the namespace and import.

Anyway, I think there is an opportunity allow this, but will take some work.
Post Reply