Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-pascal / 2019-06

Virtual object methods

15 messages · 7 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Ryan Joseph

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

Reply by email

Jonas Maebe
to Ryan Joseph
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

Reply by email

Stefan V. Pantazi
to Ryan Joseph: Why do I get a runtime error with this? ============================== {$mode objfpc}…

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.
Ryan Joseph wrote 45 lines
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 - https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
_______________________________________________________

Reply by email

Ryan Joseph
to Stefan V. Pantazi
Show quoted text 7 lines
On Jun 27, 2019, at 4:42 PM, Stefan V. Pantazi 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

Reply by email

Ryan Joseph
to Ben Grasset
On Jun 27, 2019, at 5:53 PM, Ben Grasset 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

Reply by email

Ben Grasset
to Ryan Joseph
PM Ryan Joseph wrote 7 lines
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.

Reply by email

Marco van de Voort
to Ryan Joseph: Heap allocate how so? Calling the constructor seems to fix this and puts the VMT table on…

Op 27/06/2019 om 23:56 schreef Ryan Joseph:

Show quoted text 5 lines
> On Jun 27, 2019, at 5:53 PM, Ben Grasset 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.

Reply by email

Ryan Joseph
to Marco van de Voort

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

Reply by email

Michael Van Canneyt
to Ryan Joseph
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.

Reply by email

Ryan Joseph
to Michael Van Canneyt
On Jul 2, 2019, at 10:32 AM, Michael Van Canneyt 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

Reply by email

Marco van de Voort
to Ryan Joseph: That’s what I thought. How costly is this? Not sure what it’s doing under the hood…

Op 2019-07-02 om 19:41 schreef Ryan Joseph:

> On Jul 2, 2019, at 10:32 AM, Michael Van Canneyt 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.

Reply by email

Sven Barth
to Michael Van Canneyt: As far as I know, it just moves a pointer in place, see:…
Michael Van Canneyt wrote 17 lines
On Tue, 2 Jul 2019, Ryan Joseph wrote: > > >> On Jul 2, 2019, at 10:32 AM, Michael Van Canneyt >> 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

Reply by email