Recent

Author Topic: Puzzled by child object behavior  (Read 15877 times)

VTwin

  • Hero Member
  • *****
  • Posts: 1227
  • Former Turbo Pascal 3 user
Puzzled by child object behavior
« on: June 22, 2011, 12:01:27 am »
I'm writing, actually translating, some code for matrix handling and ran into behavior I do not understand. I chose to make the matrixes objects to use dynamic allocation. Here is the problem:

A general matrix is defined something like this:
Code: [Select]
type
  TMatrix = object
  protected
    fElements: array of double;
    function  GetElement(i: integer): double;
    procedure SetElement(i: integer; d: double);
  public
    property  Element[i: integer]: double read GetElement write SetElement; default;
    procedure Dim(n: integer);
  end;

implementation

procedure TMatrix.Dim(n: integer);
begin
  SetLength(fElements, n);
end;

function TMatrix.GetElement(i: integer): double;
begin
  result := fElements[i];
end;

procedure TMatrix.SetElement(i: integer; d: double);
begin
  fElements[i] := d;
end;

That seems to work quite well.

Then I define a child to do something more specific:

Code: [Select]
type
  TMatrix4 = object(TMatrix)
  public
    procedure DoSomething;
  end;

implementation

procedure TMatrix4.DoSomething;
var
  t: TMatrix4;
begin
   t.Dim(4);  // <--- gives EXC_BAD_ACCESS in TMatrix.Dim
   t[2] := 2;
   ShowMessage(Format('t[2] = %n', [t[2]]));
end;     

Using them like so:
Code: [Select]
procedure TForm1.Button1Click(Sender: TObject);
var
  m: TMatrix;
  m4: TMatrix4;
begin
  m.Dim(3);
  m[0] := 0;
  ShowMessage(Format('m[0] = %n', [m[0]]));
  m4.Dim(4);
  m4[1] := 1;
  ShowMessage(Format('m4[1] = %n', [m4[1]]));
  m4.DoSomething;
end;

works fine until calling DoSomething, which gives a bad access error when dimensioning 't'.

It is not clear to me why this should be a problem. Can anyone explain to me why this code does not work?

Cheers,
Frederick
« Last Edit: June 22, 2011, 12:06:42 am by Frederick »
“Talk is cheap. Show me the code.” -Linus Torvalds

Free Pascal Compiler 3.2.2
macOS 15.3.2: Lazarus 3.8 (64 bit Cocoa M1)
Ubuntu 18.04.3: Lazarus 3.8 (64 bit on VBox)
Windows 7 Pro SP1: Lazarus 3.8 (64 bit on VBox)

Blaazen

  • Hero Member
  • *****
  • Posts: 3241
  • POKE 54296,15
    • Eye-Candy Controls
Re: Puzzled by child object behavior
« Reply #1 on: June 22, 2011, 12:24:19 am »
Try change "object" to "class" in declaration and modify code:
Code: [Select]
procedure TForm1.Button1Click(Sender: TObject);
var
  m: TMatrix;
  m4: TMatrix4;
begin
  m:=TMatrix.Create;
  m.Dim(3);
  m[0] := 0;
  ShowMessage(Format('m[0] = %n', [m[0]]));
  m4:=TMatrix4.Create;
  m4.Dim(4);
  m4[1] := 1;
  ShowMessage(Format('m4[1] = %n', [m4[1]]));
  m4.DoSomething;
end;     
and
Code: [Select]
procedure TMatrix4.DoSomething;
    var
      t: TMatrix4;
    begin
      t:=TMatrix4.Create;
       t.Dim(4);  // <--- gives EXC_BAD_ACCESS in TMatrix.Dim
       t[2] := 2;
       ShowMessage(Format('t[2] = %n', [t[2]]));
    end;         
Lazarus 2.3.0 (rev main-2_3-2863...) FPC 3.3.1 x86_64-linux-qt Chakra, Qt 4.8.7/5.13.2, Plasma 5.17.3
Lazarus 1.8.2 r57369 FPC 3.0.4 i386-win32-win32/win64 Wine 3.21

Try Eye-Candy Controls: https://sourceforge.net/projects/eccontrols/files/

VTwin

  • Hero Member
  • *****
  • Posts: 1227
  • Former Turbo Pascal 3 user
Re: Puzzled by child object behavior
« Reply #2 on: June 22, 2011, 12:47:53 am »
Thanks Blaazen,

That does indeed work, but I was trying to do it with dynamic allocation. If I use objects instead of classes, I don't have to worry about freeing them, as they are deallocated when they go out of scope, like strings. This was inspired by a library I came across called 'dynmatrix' that does this.

It seems to work quite well, but I bumped into this behavior that does not make sense to me. Apparently the child has issues referring to the parent array when called from within it's own method. This does not happen when the parent TMatrix uses a TMatrix in it's  own methods.

I may end up using classes as you suggest, or just use a lot of array functions, but using objects seems more convenient.

Cheers,
Frederick
“Talk is cheap. Show me the code.” -Linus Torvalds

Free Pascal Compiler 3.2.2
macOS 15.3.2: Lazarus 3.8 (64 bit Cocoa M1)
Ubuntu 18.04.3: Lazarus 3.8 (64 bit on VBox)
Windows 7 Pro SP1: Lazarus 3.8 (64 bit on VBox)

VTwin

  • Hero Member
  • *****
  • Posts: 1227
  • Former Turbo Pascal 3 user
Re: Puzzled by child object behavior
« Reply #3 on: June 22, 2011, 12:53:11 am »
Maybe I am trying to do this the wrong way, but it seemed what I am doing was legitimate. Are 'objects' to be avoided?

Edit: To use classes I'd need to add:

m.Free;
m4.Free;
t.Free;

as well, correct?
« Last Edit: June 22, 2011, 01:03:57 am by Frederick »
“Talk is cheap. Show me the code.” -Linus Torvalds

Free Pascal Compiler 3.2.2
macOS 15.3.2: Lazarus 3.8 (64 bit Cocoa M1)
Ubuntu 18.04.3: Lazarus 3.8 (64 bit on VBox)
Windows 7 Pro SP1: Lazarus 3.8 (64 bit on VBox)

VTwin

  • Hero Member
  • *****
  • Posts: 1227
  • Former Turbo Pascal 3 user
Re: Puzzled by child object behavior
« Reply #4 on: June 22, 2011, 01:31:52 am »
Aside from the memory allocation issue, the other point that I was concerned about was the VMT pointer used by a class over an objects.

I may have thousands of these in memory and was trying to reduce their memory impact. This concern may just be a relict of my programming on machines with limited memory, or perhaps I don't fully understand how it works. Is it not true that for 2 doubles, I get:

object = double + double
class = double + double + pointer

Are objects obsolete, or are they still useful?
“Talk is cheap. Show me the code.” -Linus Torvalds

Free Pascal Compiler 3.2.2
macOS 15.3.2: Lazarus 3.8 (64 bit Cocoa M1)
Ubuntu 18.04.3: Lazarus 3.8 (64 bit on VBox)
Windows 7 Pro SP1: Lazarus 3.8 (64 bit on VBox)

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 12202
  • Debugger - SynEdit - and more
    • wiki
Re: Puzzled by child object behavior
« Reply #5 on: June 22, 2011, 12:26:07 pm »
Hardly anyone uses "object" anymore. But it is still allowed to be used.

However, IIRC there was some discussion on the mail list: There is some bug with inheritance. It's been there forever, and afaik no plans exist to fix it. (I guess a well written patch may be accepted..., to be discussed on fpc mail list)

VTwin

  • Hero Member
  • *****
  • Posts: 1227
  • Former Turbo Pascal 3 user
Re: Puzzled by child object behavior
« Reply #6 on: June 22, 2011, 02:20:59 pm »
Thanks Martin,

That is very helpful. I conclude that objects are provided mostly for backwards compatibility. It therefore does not make sense to dwell on issues with objects, and I will implement matrixes as classes.

At this point it is easy enough to change them, as I am just completing the matrix units, and not yet working on the units that depend on them.

I am also the overloading operators, and find that Free Pascal operator overloading is more like C++ than Delphi. I suppose Delphi compatibility is not essential. My other option is to go back to dynamic arrays and functions. Take your pick:

c := MPlus(a, b);
c := a.Plus(b);
c := a + b;

The outcome is the same.

Thanks again both, any additional comments appreciated.

Cheers,
Frederick
“Talk is cheap. Show me the code.” -Linus Torvalds

Free Pascal Compiler 3.2.2
macOS 15.3.2: Lazarus 3.8 (64 bit Cocoa M1)
Ubuntu 18.04.3: Lazarus 3.8 (64 bit on VBox)
Windows 7 Pro SP1: Lazarus 3.8 (64 bit on VBox)

VTwin

  • Hero Member
  • *****
  • Posts: 1227
  • Former Turbo Pascal 3 user
Re: Puzzled by child object behavior
« Reply #7 on: June 22, 2011, 02:27:42 pm »
BTW, if there is to be discussion of patching the object bug, I can provide a copy of the Lazarus program that the above code is from.
“Talk is cheap. Show me the code.” -Linus Torvalds

Free Pascal Compiler 3.2.2
macOS 15.3.2: Lazarus 3.8 (64 bit Cocoa M1)
Ubuntu 18.04.3: Lazarus 3.8 (64 bit on VBox)
Windows 7 Pro SP1: Lazarus 3.8 (64 bit on VBox)

Blaazen

  • Hero Member
  • *****
  • Posts: 3241
  • POKE 54296,15
    • Eye-Candy Controls
Re: Puzzled by child object behavior
« Reply #8 on: June 22, 2011, 02:50:31 pm »
Quote
I am also the overloading operators, and find that Free Pascal operator overloading is more like C++ than Delphi. I suppose Delphi compatibility is not essential.
AFAIK freepascal supported overloaded operators from 1999. Delphi introduced them in 2002. It is the reason.
http://community.freepascal.org:10000/bboards/message?message_id=331841&forum_id=24082
Lazarus 2.3.0 (rev main-2_3-2863...) FPC 3.3.1 x86_64-linux-qt Chakra, Qt 4.8.7/5.13.2, Plasma 5.17.3
Lazarus 1.8.2 r57369 FPC 3.0.4 i386-win32-win32/win64 Wine 3.21

Try Eye-Candy Controls: https://sourceforge.net/projects/eccontrols/files/

VTwin

  • Hero Member
  • *****
  • Posts: 1227
  • Former Turbo Pascal 3 user
Re: Puzzled by child object behavior
« Reply #9 on: June 22, 2011, 03:32:06 pm »
Quote
I am also the overloading operators, and find that Free Pascal operator overloading is more like C++ than Delphi. I suppose Delphi compatibility is not essential.
AFAIK freepascal supported overloaded operators from 1999. Delphi introduced them in 2002. It is the reason.
http://community.freepascal.org:10000/bboards/message?message_id=331841&forum_id=24082

Good to know, Delphi is behind the curve.

Free Pascal is awesome!
“Talk is cheap. Show me the code.” -Linus Torvalds

Free Pascal Compiler 3.2.2
macOS 15.3.2: Lazarus 3.8 (64 bit Cocoa M1)
Ubuntu 18.04.3: Lazarus 3.8 (64 bit on VBox)
Windows 7 Pro SP1: Lazarus 3.8 (64 bit on VBox)

Carver413

  • Full Member
  • ***
  • Posts: 119
Re: Puzzled by child object behavior
« Reply #10 on: June 22, 2011, 06:53:59 pm »
if you are using fpc 2.51 you can define your matrix's as records as I have done. only draw back is no inheritance but thats not really a problem. then
you can have arrays of matrices.see advance records
http://wiki.freepascal.org/FPC_New_Features_Trunk   

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 12717
  • FPC developer.
Re: Puzzled by child object behavior
« Reply #11 on: June 22, 2011, 09:03:01 pm »
TP objects are not safe with automated types if not instantiated with NEW

There is a bugreport for this, but since it is Delphi compatible, that is a sleeper.

VTwin

  • Hero Member
  • *****
  • Posts: 1227
  • Former Turbo Pascal 3 user
Re: Puzzled by child object behavior
« Reply #12 on: June 23, 2011, 01:00:55 am »
if you are using fpc 2.51 you can define your matrix's as records as I have done. only draw back is no inheritance but thats not really a problem. then
you can have arrays of matrices.see advance records
http://wiki.freepascal.org/FPC_New_Features_Trunk

Carver,

I am currently using 2.4.2, but just read through the Delphi description. The new record features look very useful for a matrix class, value types with constructors. In some ways they are similar to the old objects without inhertance. I may upgrade to 2.51 and try them out. Thank you for the suggestion.

Cheers,
Frederick


Edit: I'm a little nervous about upgrading though, does it cause problems for Lazarus?
« Last Edit: June 23, 2011, 01:14:31 am by Frederick »
“Talk is cheap. Show me the code.” -Linus Torvalds

Free Pascal Compiler 3.2.2
macOS 15.3.2: Lazarus 3.8 (64 bit Cocoa M1)
Ubuntu 18.04.3: Lazarus 3.8 (64 bit on VBox)
Windows 7 Pro SP1: Lazarus 3.8 (64 bit on VBox)

VTwin

  • Hero Member
  • *****
  • Posts: 1227
  • Former Turbo Pascal 3 user
Re: Puzzled by child object behavior
« Reply #13 on: June 23, 2011, 01:05:52 am »
TP objects are not safe with automated types if not instantiated with NEW

There is a bugreport for this, but since it is Delphi compatible, that is a sleeper.

Thanks Marcov,

Does that mean it is a bug in Delphi too? I guess I will just avoid using them, they appear mostly depreciated.

Frederick
“Talk is cheap. Show me the code.” -Linus Torvalds

Free Pascal Compiler 3.2.2
macOS 15.3.2: Lazarus 3.8 (64 bit Cocoa M1)
Ubuntu 18.04.3: Lazarus 3.8 (64 bit on VBox)
Windows 7 Pro SP1: Lazarus 3.8 (64 bit on VBox)

Carver413

  • Full Member
  • ***
  • Posts: 119
Re: Puzzled by child object behavior
« Reply #14 on: June 23, 2011, 03:47:33 am »


Carver,

I am currently using 2.4.2, but just read through the Delphi description. The new record features look very useful for a matrix class, value types with constructors. In some ways they are similar to the old objects without inhertance. I may upgrade to 2.51 and try them out. Thank you for the suggestion.

Cheers,
Frederick


Edit: I'm a little nervous about upgrading though, does it cause problems for Lazarus?
On linux it is quite a pain, mostly do to my lack of knowlege of linux. still quite a linux nob. downloading fpc from the svn and compliling easy ( must compile 3 times).
getting lazarus svn and compiling easy. getting lazarus to like fpc 2.51 hard. there are old configs left from the old lazarus that make it insist on an older fpc. where are they , dont know. after spending about a day tring different methods I managed to wipe out these configs and all worked well.if I had to do it again I would be just as lost as the first time.was it worth it? yes, I really like working with these advanced record types.

 

TinyPortal © 2005-2018