Virtual object methods

classic Classic list List threaded Threaded
15 messages Options
Reply | Threaded
Open this post in threaded view
|

Virtual object methods

Ryan Joseph-2
Why do I get a runtime error with this?

==============================

{$mode objfpc}

program test;

// http://wiki.freepascal.org/Programming_Using_Objects
// http://wiki.freepascal.org/Programming_Using_Objects_Page_2

type
  TA = object
    procedure DoThis; virtual;
  end;

procedure TA.DoThis;
begin
  writeln('TA.DoThis');
end;

type
  TB = object (TA)
    procedure DoThis; virtual;
  end;

procedure TB.DoThis;
begin
  writeln('TB.DoThis');
end;

var
  obj: TB;
begin
  obj.DoThis;
end.


Regards,
        Ryan Joseph

_______________________________________________
fpc-pascal maillist  -  [hidden email]
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: Virtual object methods

Jonas Maebe-3
On 27/06/2019 22:17, Ryan Joseph wrote:
> Why do I get a runtime error with this?

tt.pp(4,6) Warning: Virtual methods are used without a constructor in "TA"
tt.pp(14,6) Warning: Virtual methods are used without a constructor in "TB"

You have to add a constructor and call it, otherwise the object VMT does
not get initialised.


Jonas
_______________________________________________
fpc-pascal maillist  -  [hidden email]
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: Virtual object methods

Stefan V. Pantazi
In reply to this post by Ryan Joseph-2
Read down the first page, the section "Objects - Dynamic Variables" -
all will become clear.

By avoiding the virtual methods, you can keep your objects static, all
stored on stack, no need for constructors. I personally find very useful
for my projects.

Find fixed example below. Hope it helps,

Stefan

// http://wiki.freepascal.org/Programming_Using_Objects
//Objects - Dynamic Variables

type
   TA = object
     constructor Init();
     procedure DoThis; virtual;
   end;

procedure TA.DoThis;
begin
   writeln('TA.DoThis');
end;

type
   PTB=^TB;
   TB = object (TA)
     procedure DoThis; virtual;
   end;

procedure TB.DoThis;
begin
   writeln('TB.DoThis');
end;

constructor TA.Init();
begin
   inherited;
end;

var

   obj: PTB;
begin
   obj:=New(PTB,Init());
   obj^.DoThis;
end.

On 6/27/19 4:17 PM, Ryan Joseph wrote:

> Why do I get a runtime error with this?
>
> ==============================
>
> {$mode objfpc}
>
> program test;
>
> // http://wiki.freepascal.org/Programming_Using_Objects
> // http://wiki.freepascal.org/Programming_Using_Objects_Page_2
>
> type
>    TA = object
>      procedure DoThis; virtual;
>    end;
>
> procedure TA.DoThis;
> begin
>    writeln('TA.DoThis');
> end;
>
> type
>    TB = object (TA)
>      procedure DoThis; virtual;
>    end;
>
> procedure TB.DoThis;
> begin
>    writeln('TB.DoThis');
> end;
>
> var
>    obj: TB;
> begin
>    obj.DoThis;
> end.
>
>
> Regards,
> Ryan Joseph
>
> _______________________________________________
> fpc-pascal maillist  -  [hidden email]
> https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
>

--
_______________________________________________________
_______________________________________________
fpc-pascal maillist  -  [hidden email]
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: Virtual object methods

Ryan Joseph-2


> On Jun 27, 2019, at 4:42 PM, Stefan V. Pantazi <[hidden email]> wrote:
>
> Read down the first page, the section "Objects - Dynamic Variables" - all will become clear.
>
> By avoiding the virtual methods, you can keep your objects static, all stored on stack, no need for constructors. I personally find very useful for my projects.
>
> Find fixed example below. Hope it helps,

I needed them on the stack though.

Regards,
        Ryan Joseph

_______________________________________________
fpc-pascal maillist  -  [hidden email]
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: Virtual object methods

Ryan Joseph-2
In reply to this post by Jonas Maebe-3


> On Jun 27, 2019, at 4:20 PM, Jonas Maebe <[hidden email]> wrote:
>
> tt.pp(4,6) Warning: Virtual methods are used without a constructor in "TA"
> tt.pp(14,6) Warning: Virtual methods are used without a constructor in "TB"

That’s what the meant! Thanks

Regards,
        Ryan Joseph

_______________________________________________
fpc-pascal maillist  -  [hidden email]
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: Virtual object methods

Ben Grasset
In reply to this post by Ryan Joseph-2
On Thu, Jun 27, 2019 at 4:17 PM Ryan Joseph <[hidden email]> wrote:
Why do I get a runtime error with this?

If you specifically need inheritance (combined with virtual methods) you should probably just use classes, because doing it with objects will require heap allocation regardless. 

_______________________________________________
fpc-pascal maillist  -  [hidden email]
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: Virtual object methods

Ryan Joseph-2


> On Jun 27, 2019, at 5:53 PM, Ben Grasset <[hidden email]> wrote:
>
> If you specifically need inheritance (combined with virtual methods) you should probably just use classes, because doing it with objects will require heap allocation regardless.
>

Heap allocate how so? Calling the constructor seems to fix this and puts the VMT table on the stack (I think anyways). Btw I’m doing this specifically as testing for a possible “advancedobjects” mode switch and the only reason to use objects is for inheritance on the stack (otherwise records or classes).

Regards,
        Ryan Joseph

_______________________________________________
fpc-pascal maillist  -  [hidden email]
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: Virtual object methods

Ben Grasset
On Thu, Jun 27, 2019 at 5:57 PM Ryan Joseph <[hidden email]> wrote:

Heap allocate how so? Calling the constructor seems to fix this and puts the VMT table on the stack (I think anyways). Btw I’m doing this specifically as testing for a possible “advancedobjects” mode switch and the only reason to use objects is for inheritance on the stack (otherwise records or classes).

I actually misunderstood what you were trying to do (read the program too quickly.) Never mind.

_______________________________________________
fpc-pascal maillist  -  [hidden email]
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: Virtual object methods

Marco van de Voort-3
In reply to this post by Ryan Joseph-2
Op 27/06/2019 om 23:56 schreef Ryan Joseph:
>> On Jun 27, 2019, at 5:53 PM, Ben Grasset <[hidden email]> wrote:
>>
>> If you specifically need inheritance (combined with virtual methods) you should probably just use classes, because doing it with objects will require heap allocation regardless.
>>
> Heap allocate how so? Calling the constructor seems to fix this and puts the VMT table on the stack (I think anyways). Btw I’m doing this specifically as testing for a possible “advancedobjects” mode switch and the only reason to use objects is for inheritance on the stack (otherwise records or classes).

The core problem remains that if you have


var  x : TA;

and somehow instantiate a TB in it (for virtual method/use
polymorphism), then the sizes of TA and  TB must match.

_______________________________________________
fpc-pascal maillist  -  [hidden email]
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: Virtual object methods

Ryan Joseph-2
Another question: what happens if you call the constructor twice? Does this create 2 VMT tables or overwrites the first?

================================================

type
  TA = object
    constructor Create;
    procedure DoThis; virtual;
  end;

procedure TA.DoThis;
begin
  writeln('TA.DoThis');
end;

constructor TA.Create;
begin
end;

type
  PB = ^TB;
  TB = object (TA)
    procedure DoThis; virtual;
  end;

procedure TB.DoThis;
begin
  writeln('TB.DoThis');
end;

var
  obj: TB;
begin
  TA(obj).Create; // creates VMT for TA
  TB(obj).Create; // creates VMT for TB+TA?
  obj.DoThis;
end.


Regards,
        Ryan Joseph

_______________________________________________
fpc-pascal maillist  -  [hidden email]
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: Virtual object methods

Michael Van Canneyt


On Tue, 2 Jul 2019, Ryan Joseph wrote:

> Another question: what happens if you call the constructor twice? Does this create 2 VMT tables or overwrites the first?

It overwrites the first. There is no such thing as '2 VMT tables'.

Michael.
_______________________________________________
fpc-pascal maillist  -  [hidden email]
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: Virtual object methods

Ryan Joseph-2


> On Jul 2, 2019, at 10:32 AM, Michael Van Canneyt <[hidden email]> wrote:
>
> It overwrites the first. There is no such thing as '2 VMT tables'.

That’s what I thought. How costly is this? Not sure what it’s doing under the hood but I’d like to know more.

Regards,
        Ryan Joseph

_______________________________________________
fpc-pascal maillist  -  [hidden email]
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: Virtual object methods

Michael Van Canneyt


On Tue, 2 Jul 2019, Ryan Joseph wrote:

>
>
>> On Jul 2, 2019, at 10:32 AM, Michael Van Canneyt <[hidden email]> wrote:
>>
>> It overwrites the first. There is no such thing as '2 VMT tables'.
>
> That’s what I thought. How costly is this? Not sure what it’s doing under the hood but I’d like to know more.

As far as I know, it just moves a pointer in place, see:
https://www.freepascal.org/docs-html/current/prog/progsu166.html#x210-2240008.2.12


Michael.
_______________________________________________
fpc-pascal maillist  -  [hidden email]
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: Virtual object methods

Marco van de Voort-2
In reply to this post by Ryan Joseph-2

Op 2019-07-02 om 19:41 schreef Ryan Joseph:
>> On Jul 2, 2019, at 10:32 AM, Michael Van Canneyt <[hidden email]> wrote:
>>
>> It overwrites the first. There is no such thing as '2 VMT tables'.
> That’s what I thought. How costly is this? Not sure what it’s doing under the hood but I’d like to know more.

You'd expect a mov of a constant to a memory location, but it is a bit
more involved, and it doesn't look very optimal. Maybe because it is
compiler generated, the optimizer doesn't run over it? (this is -O4 code)


P$PROGRAM$_$TA_$__$$_CREATE$$LONGBOOL:
# [13] begin
     pushl    %ebp
     movl    %esp,%ebp
     leal -8(%esp),%esp                                           //
creates stackspace
# Var $vmt located at ebp-4, size=OS_32
# Var $self located at ebp-8, size=OS_32
     movl    %eax,-8(%ebp)
     movl    %edx,-4(%ebp)
     leal    -4(%ebp),%edx                                     // self,
     movl    -8(%ebp),%eax
     movl    $0,%ecx
     call    fpc_help_constructor
     movl    %eax,-8(%ebp)                                // save result
on stack.
     testl    %eax,%eax
.Lj26:
.Lj15:
# [14] end;
     movl    -8(%ebp),%eax                               // and reload
that result. All instructions after call are no effective purpose.
     leave
     ret


     movl    $VMT_$P$PROGRAM_$$_TA,%edx
     movl    $U_$P$PROGRAM_$$_OBJ,%eax
     call    P$PROGRAM$_$TA_$__$$_CREATE$$LONGBOOL // tried to inline
ta.create, not accepted.

_______________________________________________
fpc-pascal maillist  -  [hidden email]
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: Virtual object methods

Free Pascal - General mailing list
In reply to this post by Michael Van Canneyt
Am 02.07.2019 um 19:43 schrieb Michael Van Canneyt:

>
>
> On Tue, 2 Jul 2019, Ryan Joseph wrote:
>
>>
>>
>>> On Jul 2, 2019, at 10:32 AM, Michael Van Canneyt
>>> <[hidden email]> wrote:
>>>
>>> It overwrites the first. There is no such thing as '2 VMT tables'.
>>
>> That’s what I thought. How costly is this? Not sure what it’s doing
>> under the hood but I’d like to know more.
>
> As far as I know, it just moves a pointer in place, see:
> https://www.freepascal.org/docs-html/current/prog/progsu166.html#x210-2240008.2.12 
>
Looking at the code posted by Marco and what fpc_help_constructor does
it seems to be a bit more...

Regards,
Sven
_______________________________________________
fpc-pascal maillist  -  [hidden email]
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal