How to overload assign operator for record in Delphi
Asked Answered
O

2

6

I want to make the type of record that uses dynamic arrays.

Using the variables A and B of this type I want to be able to perform operations A: = B (and other) and be able to modify the content of A without modification B like in snipped code below:

    type
      TMyRec = record
        Inner_Array: array of double;
      public
        procedure SetSize(n: integer);
        class operator Implicit(source: TMyRec): TMyRec;
      end;

    implementation

    procedure TMyRec.SetSize(n: integer);
    begin
      SetLength(Inner_Array, n);
    end;

    class operator TMyRec.Implicit(source: TMyRec): TMyRec;
    begin
    //here I want to copy data from source to destination (A to B in my simple example below)
    //but here is the compilator error
    //[DCC Error] : E2521 Operator 'Implicit' must take one 'TMyRec' type in parameter or result type
    end;


    var
      A, B: TMyRec;
    begin
      A.SetSize(2);
      A.Inner_Array[1] := 1;
      B := A;
      A.Inner_Array[1] := 0;
//here are the same values inside A and B (they pointed the same inner memory)

There are two problems:

  1. when I don't use overriding assigning operator in my TMyRec, A:=B means A and B (their Inner_Array) are pointing the same place in memory.
  2. to avoid problem 1) I want to overload assign operator using:

    class operator TMyRec.Implicit(source: TMyRec): TMyRec;

but compilator (Delphi XE) says:

[DCC Error] : E2521 Operator 'Implicit' must take one 'TMyRec' type in parameter or result type

How to resolve this problems. I read several similar posts on stackoverflow but they don't work (if I understood they well) on my situation.

Artik

Octavie answered 31/7, 2013 at 20:5 Comment(7)
Introduce a TMyRec.Clone function instead.Stig
You should make your Inner_Array immutable; code like A.Inner_Array[1] := 1; will be forbidden - any write to Inner_Array should create a new array instance. Read also sergworks.wordpress.com/2013/04/10/… for some more hints.Guimond
@user246408 Immutable vector/matrix types are usually inconvenient and lead to poor performance. For example, many matrix algorithms operate in place.Segno
Thank you.I was convinced for your opinion.Octavie
There is a way to catch assignment A:=B and copy data from A to B, if you are willing to abuse the language.Durgy
thedelphigeek.com/2015/01/…Disqualification
Related question: #953651Disqualification
S
7

It is not possible to overload the assignment operator. This means that what you are attempting to do is not possible.


Edit: It is possible now - http://docwiki.embarcadero.com/RADStudio/Sydney/en/Custom_Managed_Records#The_Assign_Operator

Segno answered 31/7, 2013 at 20:14 Comment(2)
Does it mean, there are no way to catch assignment A:=B and copy data from A to B?Octavie
It is possible to introduce a COW functionality on dynamic arrays. This will take care of the cloning when writing to the array, just as the String type works. It's a bit messy, but I managed to make it work. I will publish the code soon. Main thing that disturbs me is that intrinsic functions like SetLength,Length, etc are not possible to introduce as operator overloads.Stig
D
0

The only known way to do it is to use pointers, which is not safe, so you must understand what you're doing.

It's something like this:

type
  PMyRec = ^TMyRec;
  TMyRec = record
    MyString : string;
    class operator Implicit(aRec : PMyRec) : TMyRec;
  end;
....
class operator TMyRec.Implicit(aRec : PMyRec) : TMyRec;
begin
  if aRec = nil then // to do something...
    raise Exception.Create('Possible bug is here!');
  Result.MyString := aRec^.MyString;
end;

And the call example should look like this:

var
  aRec1, aRec2 : TMyRec;
begin
  aRec1.MyString := 'Hello ';
  aRec2.MyString := 'World';
  writeln(aRec1.MyStr, aRec2.MyStr);
  aRec2 := @aRec1;
  writeln(aRec1.MyStr, aRec2.MyStr);
end.
Declinate answered 26/10, 2018 at 7:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.