views:

441

answers:

4

Hi, I've got a lot of older code that uses the old-style pascal object type that I'm trying to get working in Delphi 2009. It compiles, but there seems to be several problems dealing with virtual methods. It appears that this problem has already been reports on Quality Central:

http://qc.embarcadero.com/wc/qcmain.aspx?d=71723

I was hoping anyone who still uses these (PatrickvL maybe?) could respond with more information. We've got A LOT of code that uses objects and if this isn't going to get fixed, we're stuck. Thanks in advance!

+4  A: 

If you're using virtual methods, then you're clearly accessing the objects by reference, not by value. That's how classes always work in Delphi, so switching to classes shouldn't be too hard.

For any object types that don't have virtual methods, you should be able to turn them into records. Records are allowed to have methods now, as well as visibility specifiers. The don't support inheritance, though.

Old-style objects have been deprecated since February 14, 1994, the release date of the first version of Delphi. They've been deteriorating ever since. You should have moved away from them years ago.

Rob Kennedy
Yes, I realize converting everything to classes will work, unfortunately doing that is a massive undertaking given the state of our code. And yes, I agree that we should have moved away from them years ago, but that was not my decision. I would like to see us convert them all to classes, but up until now they worked fine so why change them, right? Perhaps this will be the catalyst to get us to convert them.
Martin Binder
Minor nit: 1995 ;-) Trust me. My wife will never let me forget that date.
Allen Bauer
@Allen,Do old-style objects are a dead thing like BDE is treated inside Embarcadero ("even if you got a thousand votes on QC we'll never put a single second in development of BDE" - I got it from reading Codegear employee response from a newsgroup question) or there's some hope?
Fabricio Araujo
+3  A: 

I must admit I had a couple of beers looking at this, just for the challenge :) You need some magic bytes. According to legend Old style objects ONLY create a space for the pointers if you use ANY virtual methods. No Virtual methods NO VMT.

The VMT pointer is ALWAYS FIRST with new style objects because they all declare virtual methods. Seems Someone forgot that with old style objects the VMT can come later. so assuming its a just one pointer this makes it work on my D2009. I'm not into the guts of the compiler, a guy called Dave Jewell who used to write for PC pro could possibly confirm that this will be stable...

Type
  PObject1 = ^TObject1;
  TObject1 = Object
    Magic: Array[0..3] of Byte; //or integer or whatever I was playing with the size
    FCount     : Integer;
    Constructor Init;
    Procedure Add; virtual; 
    Procedure Deduct; virtual; 
    end;

Type
  PObject2   = ^TObject2;
  TObject2   = Object(TObject1)
    Constructor Init;
    end;

Then after construction these work:

.
.
.
Object2^.Add;
Object2^.Deduct;

and I get the appropriate console output

I added an additional proc just to make sure that it worked for 2 virtuals :)

Incidentally they work whether you put the ^ or not 2009 knows what you mean :(

Lacking a proper fix from embracodeland You still may still have to alter each BASE object definition. Hopefully you could do it with find and insert/replace or Grep... Good luck.

Despatcher
Unfortunately this doesn't work for me. Try defining the Add or Deduct method again in your descendant class (as virtual)...that should crash. I think you might be on the right track though. In my case the descendant object is defined in another unit. I've noticed that if I remove all variables from the base object, it appears to work fine. Alternatively, if I declare the descendant object in the same unit as the base object, it also works fine even with variables declared in the base object. Thanks a lot for taking the time to look at this, I appreciate it!
Martin Binder
+2  A: 

Ok - Done that - I cannot get it to fail.... Is your D2009 Fully Patched? Project/Compiler Options?

For absolute certainty and comparison here are my units:

---------------Project File

program testD2009;

{$APPTYPE CONSOLE}

uses
  SysUtils,
  Object1U in 'Object1U.pas',
  Object2U in 'Object2U.pas';


Var
  Object1 : PObject1;
  Object2 : PObject2;
begin
  try
    Object1 := New(PObject1,Init);
    Object1^.Add;
    Object1^.Deduct;

    Object2 := New(PObject2,Init);
    Object2^.Add;
    Object2^.Deduct;
    readln;
  except
    on E:Exception do
      Writeln(E.Classname, ': ', E.Message);
  end;
end.

--------------Object1 unit

unit Object1U;

interface

uses SysUtils;

Type
  PObject1 = ^TObject1;
  TObject1 = Object
    Magic: Array[0..3] of Byte;
    FCount     : Integer;
    Constructor Init;
    Procedure Add; virtual; { removing virtual allows the program to run }
    Procedure Deduct; virtual; { removing virtual allows the program to run }
    end;

implementation


Procedure TObject1.Add;
begin
  Writeln('Object1 Add');
end;

procedure TObject1.Deduct;
begin
  Writeln('Object1 Deduct');
end;

Constructor TObject1.Init;
begin
  inherited;
  FCount      := 0;
  Writeln('TObject1 Init');
end;

end.

----------------Object 2 unit

unit Object2U;

interface

uses Object1U;

Type
  PObject2   = ^TObject2;
  TObject2   = Object(TObject1)
    Constructor Init;
    Procedure Add; virtual; { removing virtual allows the program to run }
    Procedure Deduct; virtual; { removing virtual allows the program to run }
   end;

implementation

procedure TObject2.Add;
begin
  Writeln('Object2 Add');
  inherited;
end;

procedure TObject2.Deduct;
begin
  Writeln('Object2 Deduct');
  inherited;
end;

Constructor TObject2.Init;
begin
  Inherited Init;
  fCount := 1;
  Writeln('TObject2:Init');
end;

end.

----------------Program Output:

TObject1 Init Object1 Add Object1 Deduct TObject1 Init TObject2:Init Object2 Add Object1 Add Object2 Deduct Object1 Deduct

Puzzled I am :). Cheers. Tim.

Despatcher
Tim- I figured out why mine's crashing and yours isn't. Try this...comment out your Init constructor in your TObject2 descendant object (I don't have one defined in my descendant objects). Then from within the Init constructor on the base object (TObject1), call Add. In theory this should be calling TObject2.Add, but instead crashes. I tested the exact same app in Delphi 2006 and it properly calls the TObjec2.Add method without crashing.
Martin Binder
@Martin: this seems like something to consider for QC, even though old objects are deprecated maybe they can restore it.
Argalatyr
@Argalatyr: My original question has the link to the QC report.
Martin Binder
A: 

I sent an e-mail to our local representatives from Embarcadero in regards to this problem and referred them to the report on Quality Central. They basically told us to move all objects to classes, so I'm guessing they're not planning on fixing this...ever. I think we've pretty much accepted that this is the way we have to go if we want to move forward, so now we just have to schedule that work before we can proceed with our upgrade to Delphi 2009.

Just wanted to thank everyone who tried to help, but I believe at this point it's a lost cause :-(

Martin Binder
Yes - It's the right thing to do. Reling on magic carries the "do not annoy a wizard... warning :( Good luck with it - You'll probably find it easier that you are imagining.
Despatcher