How much information about a type is remembered at runtime?

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

How much information about a type is remembered at runtime?

Postby wallyg » Sep 16, 2018 21:42

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
Posts: 9177
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

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

Postby fxm » Sep 17, 2018 6:25

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
Posts: 9177
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

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

Postby fxm » Sep 17, 2018 6:48

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
Posts: 9177
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

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

Postby fxm » Sep 17, 2018 8:36

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: 88
Joined: May 08, 2009 7:08
Location: Tucson Arizona

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

Postby wallyg » Sep 17, 2018 21:12

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
Posts: 9177
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

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

Postby fxm » Sep 17, 2018 21:32

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

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

Postby wallyg » Sep 17, 2018 21:50

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
Posts: 922
Joined: Jul 25, 2017 17:22
Location: Argentina

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

Postby paul doe » Sep 17, 2018 23:36

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: 88
Joined: May 08, 2009 7:08
Location: Tucson Arizona

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

Postby wallyg » Sep 17, 2018 23:41

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

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

Postby paul doe » Sep 18, 2018 1:01

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
Posts: 9177
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

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

Postby fxm » Sep 18, 2018 5:55

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: 88
Joined: May 08, 2009 7:08
Location: Tucson Arizona

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

Postby wallyg » Sep 19, 2018 20:00

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

Return to “General”

Who is online

Users browsing this forum: No registered users and 25 guests