real classes and one pass compiler

General discussion for topics related to the FreeBASIC project or its community.
Post Reply
RockTheSchock
Posts: 252
Joined: Mar 12, 2006 16:25

real classes and one pass compiler

Post by RockTheSchock »

I am far from being a compiler expert, but i just had an idea.

I have many situations where i would like to make cyclic references in types without the need to use pointer and type aliases. Wouldn't it be possible to make byref fields in types which hide the pointers to objects. Why is there even a type alias needed there? You could just assume if you have a non standard data type and it's a pointer (or reference) to a new symbolname it has to be the name of a not yet defined type or class. Because the size of that field is known at this point you can just define the type.

Am i right assuming that this code with types and pointers should be theoratically possible to compile by a one pass compiler?

Code: Select all

Type Person
	firstname As String
	lastname As String
	birthdate As Integer
End Type

Type Parent extends Person
	childs(Any) As Child Ptr
End Type

Type Child extends Person
	father As Parent Ptr
	mother As Parent Ptr
End Type


Maybe there could be byref in types to hide pointers

Code: Select all

Type Parent extends Person
	childs(Any) ByRef As Child 
End Type

Type Child extends Person
	father ByRef As Parent 
	mother ByRef As Parent 
End Type

To make it even shorter you could assume for classes that all fields of a class are just references to the the instance of an object.
So you could even omit byref keyword in classes.

Code: Select all

Class Parent extends Person
	childs(Any) As Child 
End Type

Class Child extends Person
	father As Parent 
	mother As Parent 
End Class
D.J.Peters
Posts: 8586
Joined: May 28, 2005 3:28
Contact:

Re: real classes and one pass compiler

Post by D.J.Peters »

Why not using ?
operator[] byref as PARENT ' [0] Father [1] Mother
or
function Father byref as PARENT
function Mother byref as PARENT

Joshy

Code: Select all

' forward declare
type PARENT_ as PARENT
type PPARENT as PARENT_ ptr

Type PERSON
  as String  firstname
  as String  lastname
  as integer birthdate
End Type

type CHILD extends PERSON
  declare function Father byref as PARENT_
  declare function Mother byref as PARENT_
  as PPARENT  m_father
  as PPARENT  m_mother
End type

type PARENT extends PERSON
  as CHILD CHILDs(Any) 
End Type


function CHILD .Father byref as PARENT
  return *m_father
end function
function CHILD .Mother byref as PARENT
  return *m_father
end function
fxm
Moderator
Posts: 12131
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: real classes and one pass compiler

Post by fxm »

For a member field, declare a reference 'Byref As' is not allowed except for a static member field.

Declare a member field 'As UDT' or 'As UDT Ptr' corresponds exactly to use 'composition' or 'aggregation'.
The choice should not be driven by a preferred syntax but rather by a functional need:
- 'composition' ('As UDT'): The Type fully contains the component object, and this one will be automatically created then destroyed at same time than the Type object.
- 'aggregation' ('As UDT Ptr'): The Type only contains a pointer to the component object, and this component object has an existence independent of the Type object (before use, this pointer must refer to an already existing component object).
fxm
Moderator
Posts: 12131
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: real classes and one pass compiler

Post by fxm »

Joshy,

Your program don't work for pointer assignment by using a byref function:
(neither with operator[] byref as PARENT)

Code: Select all

' forward declare
type PARENT_ as PARENT
type PPARENT as PARENT_ ptr

Type PERSON
  as String  firstname
  as String  lastname
  as integer birthdate
End Type

type CHILD extends PERSON
  declare function Father byref as PARENT_
  declare function Mother byref as PARENT_
  as PPARENT  m_father
  as PPARENT  m_mother
End type

type PARENT extends PERSON
  as CHILD CHILDs(Any)
End Type


function CHILD .Father byref as PARENT
  return *m_father
end function
function CHILD .Mother byref as PARENT
  return *m_mother
end function

dim as PARENT f, m
dim as CHILD c
c.Father() = f
c.Mother() = m

Sleep
Aborting due to runtime error 12 ("segmentation violation" signal) in .....\FBIde0.4.6r4_fbc1.05.0\FBIDETEMP.bas::()
- Because do:
*m_father = f
is not equivalent to:
m_father = @f
- Another syntax like (as for true references):
@(c.Father()) = @f
is forbidden, because in order to return by reference, Father() returns in interne only a temporary pointer by value.

An alternative is to use a property (with the setter assigning the pointer value):

Code: Select all

' forward declare
type PARENT_ as PARENT
type PPARENT as PARENT_ ptr

Type PERSON
  as String  firstname
  as String  lastname
  as integer birthdate
End Type

type CHILD extends PERSON
  declare property Father byref as PARENT_
  declare property Father (byref as PARENT_)
  declare property Mother byref as PARENT_
  declare property Mother (byref as PARENT_)
  as PPARENT  m_father
  as PPARENT  m_mother
End type

type PARENT extends PERSON
  as CHILD CHILDs(Any)
End Type


property CHILD .Father byref as PARENT
  return *m_father
end property
property CHILD .Father (byref p as PARENT_)
  m_father = @p
end property
property CHILD .Mother byref as PARENT
  return *m_father
end property
property CHILD .Mother (byref p as PARENT_)
  m_mother = @p
end property

dim as PARENT f, m
dim as CHILD c
c.Father = f
c.Mother = m

Sleep
RockTheSchock
Posts: 252
Joined: Mar 12, 2006 16:25

Re: real classes and one pass compiler

Post by RockTheSchock »

fxm wrote:'aggregation' ('As UDT Ptr'): The Type only contains a pointer to the component object, and this component object has an existence independent of the Type object (before use, this pointer must refer to an already existing component object).
No, the pointer must refer to a definition of an object (let's call it a class).

EDIT: The pointers' value of the instance refers to the instance of an object of type "udt" runtime!
The line in a type like "as udt ptr" refers to the definition of the type "udt". compile time!

fxm wrote:The choice should not be driven by a preferred syntax but rather by a functional need
The functional need is to not have different symbol names for the same class. Type aliases are getting nasty when you use a lot of classes with cyclic references. A prefered syntax which in half number code of lines is also a functional need! Or shall I prefer asm over freebasic?

Back to the point:

Why do i need a type alias? Types are used as definitions of objects(classes). In a type "someobject As UDT Ptr" means if UDT is not a builtin datatype it must be a complex type (class with constructor). If the Type "UDT" is defined later we must only assure that it will have a constrcuctor ( extends object implicitly or just throw an error if there isnt one) and if the type is intantiated, eg. in a dim, with var or in a procedure as parameter than the compiler needs to check if the type is actually defined.

The other suggestions with references in types and class keyword using memberobjects automatically as references where just suggestions for a syntactic sugar but the main questions remains: Does a one pass compiler like fbc really need type aliases for this sort of thing? It's a theoratical questions for future feature.
fxm
Moderator
Posts: 12131
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: real classes and one pass compiler

Post by fxm »

A typed pointer is a data-type used to hold addresses of instantiated objects from a class. The kind of pointer (the class) determines only how the data at the address are interpreted when the pointer is dereferenced.
In OOP, you can even manage a derived object while using a base pointer.
fxm
Moderator
Posts: 12131
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: real classes and one pass compiler

Post by fxm »

For now, no problem with this:

Code: Select all

Type Person
    firstname As String
    lastname As String
    birthdate As Integer
End Type

Type Parent extends Person
    childs(Any) As Person Ptr
End Type

Type Child extends Person
    father As Person Ptr
    mother As Person Ptr
End Type


Dim As Parent f, m
f.firstname = "John"
m.firstname = "Julia"

Dim As Child c
c.father = @f
c.mother = @m
c.firstname = "Jo"

Redim f.childs(0)
f.childs(0) = @c
Redim m.childs(0)
m.childs(0) = @c

Print f.childs(0)->firstname
Print m.childs(0)->firstname
Print
Print c.father->firstname
Print c.mother->firstname
Print

Sleep
For the next steps, to see!
marcov
Posts: 3462
Joined: Jun 16, 2005 9:45
Location: Netherlands
Contact:

Re: real classes and one pass compiler

Post by marcov »

RockTheSchock wrote:I am far from being a compiler expert, but i just had an idea.

I have many situations where i would like to make cyclic references in types without the need to use pointer and type aliases. Wouldn't it be possible to make byref fields in types which hide the pointers to objects. Why is there even a type alias needed there? You could just assume if you have a non standard data type and it's a pointer (or reference) to a new symbolname it has to be the name of a not yet defined type or class. Because the size of that field is known at this point you can just define the type.

Am i right assuming that this code with types and pointers should be theoratically possible to compile by a one pass compiler?
Yes. As long as the compiler knows the class is a reference type it will work, for the same reason as a forward pointer references works. As long as the compiler can determine size. (and you use no other properties of the type before the "full" declaration)

Delphi/Freepascal follow this model where classes are implicit pointers (though still with non GC memory management), but this means local instantiation goes the way of the dodo.
Last edited by marcov on Dec 29, 2015 16:26, edited 1 time in total.
Tourist Trap
Posts: 2958
Joined: Jun 02, 2015 16:24

Re: real classes and one pass compiler

Post by Tourist Trap »

RockTheSchock wrote:I have many situations where i would like to make cyclic references in types without the need to use pointer and type aliases. Wouldn't it be possible to make byref fields in types which hide the pointers to objects. Why is there even a type alias needed there? You could just assume if you have a non standard data type and it's a pointer (or reference) to a new symbolname it has to be the name of a not yet defined type or class. Because the size of that field is known at this point you can just define the type.
Hi RockTheShock, nice idea.

However, at keyword level instead of simply "type", what about "reftype" versus "valtype" (left aside this naming convention, just convenient for the discussion)?

I mean, I think very useful to be able to refere expressely to pointers when needed at udt member field level (when writting declarations). This has been visual basic policy to forbid explicit call to pointers anywhere, unless seemingly one uses pkinvoke or things very peculiars and poorly documented. After a while following this way, I find it clearly to be a mistake. One needs to refere to memory address explicitely when needed in order to figure out clearely what is really going on, and not to be coding blindly which leads to bad results.

This left aside, there is a good thing in vb. The classes are always references, or I think we can say equivalently, they are pointers. So we always refere to classes variables the way we would call "byref" in fb. And in another hand,
another object named a "structure" in vb -and still very close to a class- exists that is declared and used the way we would call "byval" in fb. This last way is the equivalent of the freebasic "type". So in some sense : vb_structure=fb_type.

Even if I've said that I wouldn't like hidding too much pointers at members fields level (inside the type declaration block), for pedagogy considerations, I'm not at all against promoting udt as "byref" by default. This proves quite efficent under vb, where declaring any class instance is byref stuff. This is very relevant if we also consider how common is the use of udts as collections (which are best implemented as pointers array unless I'm totally wrong here).
I think we can even see collections as array of references, so if types are references by default this makes sense. (...maybe it's what type aliasing is already doing after all?_?)

So why not simply add at the type keyword level some modifier to specify byval, or byref?

Maybe also it's what you have implicitely meant when it has been refered to "real classes" in your introduction title.
RockTheSchock
Posts: 252
Joined: Mar 12, 2006 16:25

Re: real classes and one pass compiler

Post by RockTheSchock »

Tourist Trap wrote:So why not simply add at the type keyword level some modifier to specify byval, or byref?
Maybe also it's what you have implicitely meant when it has been refered to "real classes" in your introduction about including byref at inner udt fields declaration level.
Hi Tourist Trap,
well, thats and the keyword class is reserved. At moment the keyword "type" is used as allmighty tool which is extended further and further. But to not break compatibility one would introduce a byval and byref modifier for udt members in types and classes. In types byval would be used implicitly while in classes "byref" and "extends object" would be used implicitly. Well freebasic does many things like c. An fb type is almost identical to a c++ struct. So why not going the way of c++ classes. maybe instead of multiple inheritance i would prefer interfaces.
Tourist Trap
Posts: 2958
Joined: Jun 02, 2015 16:24

Re: real classes and one pass compiler

Post by Tourist Trap »

RockTheSchock wrote:not break compatibility one would introduce a byval and byref modifier for udt members in types and classes. In types byval would be used implicitly while in classes "byref" and "extends object" would be used implicitly.
I see. I think you are right after all, that byref keyword should be compatible with a member field declaration. I'm not sure what will be done for classes. But very probably, the way you describe the things is consistant with this concept.
RockTheSchock wrote:Well freebasic does many things like c. An fb type is almost identical to a c++ struct. So why not going the way of c++ classes. maybe instead of multiple inheritance i would prefer interfaces.
Having tried interfaces in vb2005, I've found them very strange, one wouldn't be able to use some class variable inside, and a lot of limitation I disliked, that one doesn't encounter with base classes.
I mean, as far as I understand the usage of interfaces, it's for providing a sort of blueprint, with a skeleton filled with void. But this is possible to do this with base classes. So I must miss something here.
Tourist Trap
Posts: 2958
Joined: Jun 02, 2015 16:24

Re: real classes and one pass compiler

Post by Tourist Trap »

RockTheSchock wrote:not break compatibility one would introduce a byval and byref modifier for udt members in types and classes. In types byval would be used implicitly while in classes "byref" and "extends object" would be used implicitly.
I see. I think you are right. So Byref keyword should be compatible with udt member field declaration.

I'm not sure what will be done for classes. But very probably, the way you describe the things is consistant with the concept.
RockTheSchock wrote:Well freebasic does many things like c. An fb type is almost identical to a c++ struct. So why not going the way of c++ classes. maybe instead of multiple inheritance i would prefer interfaces.
Having tried interfaces in vb2005 (I don't know them in C++), I've found them very strange, one wouldn't be able to use some class variable inside, and a lot of limitation I disliked, that one doesn't encounter with base classes.
I mean, as far as I understand the usage of interfaces, it's for providing a sort of blueprint, with a skeleton filled with void. But this is possible to do this with base classes. So I must miss something here.
RockTheSchock
Posts: 252
Joined: Mar 12, 2006 16:25

Re: real classes and one pass compiler

Post by RockTheSchock »

Tourist Trap wrote:I mean, as far as I understand the usage of interfaces, it's for providing a sort of blueprint, with a skeleton filled with void. But this is possible to do this with base classes. So I must miss something here.
Multiple inheritance with classes has many sideeffects which can get very complex. With interfaces there is no ambiguity as implementation is provided by the implementation class. You get the possibility to use a second hierarchy with multiple inheritance an example could be:

Code: Select all

'-------------
'Interfaces.bi
'-------------
Interface Printable
	Declare Sub Print()	
	Declare Function SelectPrinter() As Printer 
End Interface

Interface Showable
	Declare Sub Show()	
End Interface

Interface Runnable
   Declare Sub run()	
End Interface

'--------
'File.bi
'--------
Type File 'abstract
	Declare Abstract Sub Open(file As String)	
	Declare Abstract Sub Close()	
End Type

Type TextFile extends File Implements Printable,Showable
	text As String
End Type

Type BasFile extends File Implements Printable,Showable,Runable
	 code As String
End Type


'---------------
'GUIComponent.bi
'---------------
Type GUIComponent implements Showable
	As Integer x,y,w,h		
End Type	



'------------
'Textfile.bas
'------------
Sub TextFile.Print()	
	'...	
End Sub
Function TextFile.SelectPrinter() As Printer 	
	'...
End Function
Sub TextFile.Show()	
	'...	
End Sub



'-----------
'CSVFile.bas
'-----------
Sub BasFile.Print()	
	'...	
End Sub
Function BasFile.SelectPrinter() As Printer 	
	'...
End Function
Sub BasFile.Show()	
	'...	
End Sub
Sub BasFile.Run()	
	'...	
End Sub

	


'----------------
'GUIComponent.bas
'---------------- 
Sub GUIComponent.Print()	
	'...	
End Sub
Function GUIComponent.SelectPrinter() As Printer 	
	'...
End Function
Sub GUIComponent.Show()	
	'...	
End Sub


'--------
'Main.bas
'--------
Dim As Showable obj(0 To 2)

obj(0) = New TextFile()
obj(0)->load("bla.txt")
obj(1) = CSVFile()
obj(1)->load("blub.csv")
obj(2) = GUIComponent()


Print "Select an action" 
Print "1. Show"
Print "2. Print"
Print "3. Run"
Dim choice As String
Do
   choice = Input(1)
Loop Until choice >= "1" And choice <= "3"


For i As Integer = 0 To 2
	If choice = "1" Then
		If *obj(i) Is Showable Then
			obj(i)->show()
		EndIf
	ElseIf choice = "2" Then	
		If *obj(i) Is Printable Then
			obj(i)->Print
		EndIf
	ElseIf choice = "3" Then
		If *obj(i) Is Runable Then
			obj(i)->Run
		EndIf

	EndIf
Next
fxm
Moderator
Posts: 12131
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: real classes and one pass compiler

Post by fxm »

Extract of the documentation about Type (Alias):
.....
A type alias can be used to allow forward declarations of parameters in procedure declarations, but only used with pointers or parameters passed by reference (excluding arrays).
.....
Why this restriction for an array when its descriptor is passed by reference?
dkl
Site Admin
Posts: 3235
Joined: Jul 28, 2005 14:45
Location: Germany

Re: real classes and one pass compiler

Post by dkl »

Although I can't explain that (compiler source code implicitly disallows it, but either way there is no reason mentioned), I did notice that the feature is rather broken anyways:
#818 Bad code generated for calls to functions with incomplete parameter types

So it's probably better to disallow it alltogether.
Post Reply