How much information about a type is remembered at runtime?

General FreeBASIC programming questions.
Post Reply
wallyg
Posts: 267
Joined: May 08, 2009 7:08
Location: Tucson Arizona

How much information about a type is remembered at runtime?

Post by wallyg »

I have the following type definitions and code

Code: Select all

type Obj
    as ushort	ObjType	' Type of this object ( 1- 317 see ObjTypes.xxx)
    as ushort	RefCount	' Number of references to this object
    ...
    declare sub ReduceRefCount(n as long)
    ...
end type

type Car Extends Obj
    as Ulong	Color
    as string	Make 
    ...
    declare function  xxx() as long
end type 
...

sub Obj.ReduceRefCount(n as long)
	This.RefCount -= n
	if This.RefCount = 0 Then
		Delete @This
	Endif
End sub

dim as Car ptr       Ford
Ford.Make = "1962 Mustang"
Ford.Color = &HFF0000FF
...
Ford.ReduceRefCount(1)

The question I have is when the line "Delete @This" is executed, will all the memory of Car get returned to the memory allocator or just the amount of memory associated with Obj? Including the memory allocated to the String Make?

Second question.
It does not look like the statement

This.xxx

would work as the second line of ReduceRefCount? Is there any simple generic way to make it work when there are hundreds of types derived from OBJ.


Third question.

Is there some way I can declare a variable "ObjType" in type OBJ that contains a FreeBasic type. So that I can store the type Car into it during the execution of the constructor for Car.

Then in a routine declared in ObjI can cast the Obj pointer @This to a Car pointer something like this

Cast(This.ObjType,@This)

And execute the Car function xxx in that OBJ routine

Code: Select all

type Obj
    as ushort	ObjType	' Type of this object ( 1- 317 see ObjTypes.xxx)
    as ushort	RefCount	' Number of references to this object
    as ???????	ObjType	' FreeBasic type of object
    ...
    declare sub ReduceRefCount(n as long)
    ...
end type

type Car Extends Obj
    as Ulong	Color
    as string	Make 
    ...
    declare function  xxx() as long
    declare Constructor
end type 
Constructor Car
	This.ObjType = Car
end Constructor
...

sub Obj.ReduceRefCount(n as long)
	This.RefCount -= n
	if This.RefCount = 0 Then
		Delete @This
	else
		Cast(This.ObjType,@This).xxx
	Endif
End sub

dim as Car ptr       Ford
Ford.Make = "1962 Mustang"
Ford.Color = &HFF0000FF
...
Ford.ReduceRefCount(1)

fxm
Moderator
Posts: 12082
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: How much information about a type is remembered at runtime?

Post by fxm »

Just 2 preliminary remarks (let's start at the beginning):
- To access a member field from an object pointer, you must use the "->" operator.
(the "." operator is used for accessing a member field from an object reference)
- To create a dynamic object, you defined an object pointer ("Ford"), but you must also allocate memory and construct data of the specified type by calling the "New" operator.
(When it becomes useless, this dynamic object will have to be suppressed by calling the "Delete" operator)

Code: Select all

dim as Car ptr       Ford = New Car
Ford->Make = "1962 Mustang"
Ford->Color = &HFF0000FF
'...
Ford->ReduceRefCount(1)
fxm
Moderator
Posts: 12082
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: How much information about a type is remembered at runtime?

Post by fxm »

wallyg wrote:The question I have is when the line "Delete @This" is executed, will all the memory of Car get returned to the memory allocator or just the amount of memory associated with Obj? Including the memory allocated to the String Make?
"Delete @This" induces 2 actions:
- first, all data associated to the Type of "@This" ("Obj Ptr" in your case) will be destroyed.
- then the allocated memory at address corresponding to the value of "@This" will be freed (whatever the type of "@This").
So in your example, the "Make" member field will be not destroyed but all memory allocated for "Obj+Car" member fields will be freed, inducing a memory leak: the "1962 Mustang" character data in your example (it starts badly).

For the rest of your questions, all you want to do seems to me obscure, twisted and unsafe, so that I do not know what to say.
fxm
Moderator
Posts: 12082
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: How much information about a type is remembered at runtime?

Post by fxm »

wallyg wrote:Third question.

Is there some way I can declare a variable "ObjType" in type OBJ that contains a FreeBasic type. So that I can store the type Car into it during the execution of the constructor for Car.

Then in a routine declared in ObjI can cast the Obj pointer @This to a Car pointer
If you want to access a derived member field from a base pointer/reference, the better method is polymorphism (by virtual member procedures). If you want access derived field data, the better is so to add associated virtual properties allowing to access these data.
All the rest is a terrible knitting unsafe.

Otherwise, the least awful would be to define "Obj Extends Object" in the type declaration, and so to be able to execute in any Obj procedure the kind of following code:

Code: Select all

If This Is Car Then
   Cast(Car Ptr, @This)->xxx
End If
wallyg
Posts: 267
Joined: May 08, 2009 7:08
Location: Tucson Arizona

Re: How much information about a type is remembered at runtime?

Post by wallyg »

fxm wrote:
wallyg wrote:Third question.

Is there some way I can declare a variable "ObjType" in type OBJ that contains a FreeBasic type. So that I can store the type Car into it during the execution of the constructor for Car.

Then in a routine declared in ObjI can cast the Obj pointer @This to a Car pointer
If you want to access a derived member field from a base pointer/reference, the better method is polymorphism (by virtual member procedures). If you want access derived field data, the better is so to add associated virtual properties allowing to access these data.
All the rest is a terrible knitting unsafe.

Otherwise, the least awful would be to define "Obj Extends Object" in the type declaration, and so to be able to execute in any Obj procedure the kind of following code:

Code: Select all

If This Is Car Then
   Cast(Car Ptr, @This)->xxx
End If
Yes this is what I want done, the problem is that there are currently 317 different types that @this can point to (many more to come over time). I wanted some generic way to do the cast without having a 317 branch If or Select statement in lots and lots of similar situations (then have to update each and every one a couple times a week as more types are added).
fxm
Moderator
Posts: 12082
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: How much information about a type is remembered at runtime?

Post by fxm »

So you can try to use sub-type polymorphism as proposed above.
wallyg
Posts: 267
Joined: May 08, 2009 7:08
Location: Tucson Arizona

Re: How much information about a type is remembered at runtime?

Post by wallyg »

Thank you.

I have not done anything like that before, so I will go back to the FB manual and try to work out how that works. Is there any other documents that go into more detail than the current standard FB manual?
paul doe
Moderator
Posts: 1730
Joined: Jul 25, 2017 17:22
Location: Argentina

Re: How much information about a type is remembered at runtime?

Post by paul doe »

wallyg wrote:Thank you.

I have not done anything like that before, so I will go back to the FB manual and try to work out how that works. Is there any other documents that go into more detail than the current standard FB manual?
I'll say that the Manual is the best place to look for this info. That, and this forum of course =D
This is a simple approach to your problem (if I understood your requirement correctly):

Code: Select all

/'
  The interface for a record in the car table
  
  Any object deriving from this interface can be added to
  the car table
'/
type ICarRecord extends Object
  declare virtual destructor()
  
  declare abstract property brand() as string
  declare abstract property year() as string
  declare abstract property color() as string
  declare abstract property model() as string
end type

destructor ICarRecord()
end destructor

/'
  A concrete implementation of the ICarRecord interface
  
  This defines a generic 'Car' object with several properties.
'/
type Car extends ICarRecord
  public:
    declare constructor( _
      byref as const string, _
      byref as const string, _
      byref as const string, _
      byref as const string )
    declare destructor() override
    
    declare property brand() as string override
    declare property model() as string override
    declare property year() as string override
    declare property color() as string override
    
  private:
    declare constructor()
    
    m_brand as string
    m_model as string
    m_year as string
    m_color as string
end type

constructor Car()
end constructor

constructor Car( _
  byref theBrand as const string, _
  byref theModel as const string, _
  byref theYear as const string, _
  byref theColor as const string )
  
  m_brand = theBrand
  m_model = theModel
  m_year = theYear
  m_color = theColor
end constructor

destructor Car()
end destructor

property Car.brand() as string
  return( m_brand )
end property

property Car.model() as string
  return( m_model )
end property

property Car.year() as string
  return( m_year )
end property

property Car.color() as string
  return( m_color )
end property

/'
  This class defines a simple table of cars
'/
type CarTable
  public:
    declare constructor()
    declare destructor()
    
    declare property records() as uinteger
    
    declare function record( _
      byval as uinteger ) as ICarRecord ptr
      
    declare sub addRecord( _
      byval as ICarRecord ptr )
    
    declare sub showReport()
  
  private:
    m_recordCount as uinteger
    m_records( any ) as ICarRecord ptr
end type

constructor CarTable()
end constructor

destructor CarTable()
  for i as integer = 0 to m_recordCount - 1
    if( m_records( i ) <> 0 ) then
      delete( m_records( i ) )
    end if
  next
end destructor

property CarTable.records() as uinteger
  return( m_recordCount )
end property

function CarTable.record( _
  byval anIndex as uinteger ) as ICarRecord ptr
  
  return( m_records( anIndex ) )
end function

sub CarTable.addRecord( _
  byval aRecord as ICarRecord ptr )
  
  m_recordCount += 1
  redim preserve m_records( 0 to m_recordCount - 1 )
  
  m_records( m_recordCount - 1 ) = aRecord
end sub

sub CarTable.showReport()
  color( 0, 7 )
  ? "Records in table: "; m_recordCount
  ? "Brand", "Model", , "Year", "Color", ""
  
  color( 7, 0 )
  for i as integer = 0 to m_recordCount - 1
    ? m_records( i )->brand;
    ? tab( 15 ); m_records( i )->model;
    ? tab( 43 ); m_records( i )->year;
    ? tab( 57 ); m_records( i )->color
  next
end sub

sub drive( byval aCar as ICarRecord ptr )
  ? "Currently driving: "; aCar->brand; " "; aCar->model
end sub

/'
  Main code
'/
'' Create a table
var aCarTable = CarTable()

'' Add some records
aCarTable.addRecord( new Car( _
  "Ford", "Mustang", "1968", "Red" ) )

aCarTable.addRecord( new Car( _
  "Alfa Romeo", "Tipo 158 Alfetta", "1947", "Blue" ) )

aCarTable.addRecord( new Car( _
  "Acura", "NSX", "1992", "Green" ) )

'' And show the number of records present in the table
aCarTable.showReport()

?

'' Simple polymorphic function
for i as integer = 0 to aCarTable.records - 1
  drive( aCarTable.record( i ) )
next

/'
  The records in the table are all read-only, but you can easily
  implement a property setter to update its values if you like.
  However, sometimes it's easier to just remove the object from the
  table, create a new one, and add it to the table again. This is
  especially true if you keep the array sorted by, say, brand or
  year.
'/
sleep()
This code implements a very simple table of cars. Only barebones functionality is implemented (namely, adding a record to the table and presenting a report). However, the table is polymorphic, and will add any record that conforms to the ICarRecord interface. I provided a simple, generic Car class that has some read-only properties, and a polymorphic drive() procedure that 'drives' each car present in the table. Is this what you're trying to do? Or are there specific methods to call for each model of car?
wallyg
Posts: 267
Joined: May 08, 2009 7:08
Location: Tucson Arizona

Re: How much information about a type is remembered at runtime?

Post by wallyg »

Thank you for your help. I will study this and apply its principles to my needs. I appreciate your help.
paul doe
Moderator
Posts: 1730
Joined: Jul 25, 2017 17:22
Location: Argentina

Re: How much information about a type is remembered at runtime?

Post by paul doe »

wallyg wrote:Thank you for your help. I will study this and apply its principles to my needs. I appreciate your help.
You're welcome. Glad to be of help =D
fxm
Moderator
Posts: 12082
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: How much information about a type is remembered at runtime?

Post by fxm »

paul doe wrote:I'll say that the Manual is the best place to look for this info.
For polymorphism, the main information is at the page: VIRTUAL
Other linked pages: ABSTRACT, OBJECT, EXTENDS, OVERRIDE
Additional pages: Operator Is (Run-time type information), BASE (member access), BASE (initializer)
wallyg
Posts: 267
Joined: May 08, 2009 7:08
Location: Tucson Arizona

Re: How much information about a type is remembered at runtime?

Post by wallyg »

I appreciate the information. I will read these together with studing the above example to help me understand the concepts better and apply them to my project.

Thanks again
Post Reply