Is there anyway to use the property like behavior?

2019-03-07 03:50发布

问题:

I have the following formula

X := X + F*(1-i div n);

Where

X, F, i, n: integer;

The code I'm using is this

F := 7; // the initial speed with no friction.
n := 10; // the animation number of steps.
Hn := n * 2 ; 
X := 0;  // first Pos
i := 1;  
J := 1;
while J < Hn do
begin
  X := X + F * (1 - i div n);
  if X > Xmax then X := 0;  <-- line (1).
  if i >= n then Dec(i)
  else Inc(i);
  Inc(J); 
end;

If it was possible I would like to use this but without class/record implementation(not inside a class/record implementation/method).not the exact syntax, just the same principle, instead of direct assignment to X the SetX is called then the result is assigned to X.

X: integer write SetX; // This is not a correct delphi syntax. I added it to explain the behavior I want. 

function SetX(aValue: integer): integer;
const
  Xmax: SomeIntegerValue;
begin
  if aValue > Xmax then result := 0  
  else result := aValue; 
end;

So I could omit Line (1). If this was possible, all the lines after the formula would be omitted and the while loop would look like this

while J < Hn do  // J will be incremented each time the loop wants to read it.    
begin
  X := X + F * (1 - i div n);
end;

Is there anyway to use the property like behavior?

Note: I'm looking for a way to alter the assignment and reading ways of a variable like you do in a property of a record/class.

回答1:

Is there anyway to use the property like approach outside a class/record?

No, property getters and setters can only be implemented in records and classes.



回答2:

You can use local function like

procedure YourProcedure;

var
  X: Integer;
  LJ: Integer;
function J: Integer;
begin
  Inc(LJ);
  Result := LJ;
end; 
procedure SetX(const AValue: Integer);
const
  Xmax: SomeIntegerValue;
begin
  if aValue > Xmax then X := 0  
  else X := aValue; 
end;
//...
begin
  while J < Hn do  // J will be incremented each time the loop wants to  read it.    
  begin
     SetX(X + F * (1 - i div n));
  end
end.


回答3:

I found a way to do what I wanted. I know that overloading the := operator is not possible, However forcing the compiler to produce the same behavior as the overloaded operator would behave is possible.

The overloading would not let me control the LSA (Left Side Argument). but it gave full control to implicitly convert any TType (in my case it is an integer) to TXinteger. So all I had to do is make sure that every operator would result in a TType which will force the compiler to implicitly convert that to a TXinteger.

Forcing the compiler to use my implicit operator every time it wants to assign something to TXinteger means I control the assignment Hence I overloaded the := operator.

the following is a test example that makes omitting Line(1) possible.

program Project4;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils;



type
   TXinteger = record
     X: integer;
     class operator Add(a, b: TXinteger): integer;
     class operator Add(a: TXinteger; b:integer): integer;
     class operator Add(a: integer; b:TXinteger): integer;
     class operator Implicit(a: Integer): TXinteger;
     class operator Implicit(a: TXinteger): Integer;
   end;

// Example implementation of Add
class operator TXinteger.Add(a, b: TXinteger): integer;
begin
  result := a.X + b.X;
end;(**)

class operator TXinteger.Add(a: TXinteger; b:integer): integer;
begin
  result := a.X + b;
end;

class operator TXinteger.Add(a: integer; b:TXinteger): integer;
begin
  result := a + b.X;
end;

class operator TXinteger.Implicit(a: Integer): TXinteger;
const
  Xmax: integer = 10;
begin
  if a > Xmax then result.X := 0 else result.X := a;
end;

class operator TXinteger.Implicit(a: TXinteger): Integer;
begin
  result := a.X;
end;

var
X: TXinteger;
Hn, F, i,J, n: integer;
begin
  try
  F := 7;
  n := 10;
  Hn := n * 2 ;
  X := 0;
  i := 1;
  J := 1;
  while J < Hn do
    begin
    X := X + F * (1 - i div n);
    // Line (1)  is gone now.
    if i >= n then Dec(i)
    else Inc(i);
    Inc(J);
    end;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.

Note: for this case it is pointless to do all of this just to omit one line of code. I wanted to share this because it gives an idea of how one could overload the := operator.

What I wanted is this:

  • Alter how X:Integer is read (value read from the variable x's storage).
  • Alter how X:Integer is assigned.

by overloading all the operators that use the value of X, I completed the first. And by forcing the compiler as explained above, I completed the second.

Thank you all for your help.