0

Given the declarations :

Unit MyUnit;

interface

type

  TMyFileStream= class(TFileStream);
  ...
  end;

var
  a1,a2,a3,a4,a5: integer;
  b1,b2,b3: boolean;
  c1: char;
  d1,d2,d3,d4: TDateTime;
  f1,f2,f3,f4,f5,f6,f7,f8: TMyFileStream // LineX
  ...

procedure MyProc;

implementation

procedure MyProc
begin

  // I wanna iterate over all integer (or any other type) variables here with a loop regardless of their count and identifier name

end;

Some specific type variables' count regularly changes in code - mostly increases as I add new functions. How can I reference them in a loop to take the same action on all of them ? I want to preserve the fact that when I add a new one, the code needs to be modified at only one place.

I've already thought of putting them in an (either static or dynamic) array, but this involves the modifocation of code at every location where they are referenced, which is much-much-much work that I wanna spare if it's possible by any means.

There's currently 38 variables I want to take an acton upon, the references' count is a multiple of it far above 100.

Hope I was clear enough. Thanks for any idea.

Peter

11
  • If you find a way to iterate variables, you'll have to modify the code everywhere they are referred. How does that differ from using arrays which require modification everywhere they're referred? Commented Dec 6, 2013 at 15:21
  • No, I wanna leave old references intact, that would be the only goal. Commented Dec 6, 2013 at 15:27
  • 2
    You should really switch to that array (you can automate that replacement). What you want would be messy. Imagine that one day you would add an integer variable which you don't want to use for that iteration, but due to some magic would be used there. Commented Dec 6, 2013 at 15:37
  • 3
    Spare time now and have a BIG BIG headache later, do yourself a favor and start refactoring NOW.... Commented Dec 6, 2013 at 15:41
  • 1
    What have integer, boolean, char, TDateTime and TMyFileStream have in common that you could perform the same action on them? You can take their addresses but then what? Commented Dec 6, 2013 at 15:51

3 Answers 3

5

Although the design smells, this is what pointers are made for:

type
  PMyFileStream = ^TMyFileStream;
  TMyFileStream= class(TFileStream)
  end;

var
  a1,a2,a3,a4,a5: integer;
  b1,b2,b3: boolean;
  c1: char;
  d1,d2,d3,d4: TDateTime;
  f1,f2,f3,f4,f5,f6,f7,f8: TMyFileStream; // LineX

function GetVarsInt: TArray<PInteger>;
begin
  result := TArray<PInteger>.Create(@a1, @a2, @a3, @a4, @a5);
end;

function GetVarsBool: TArray<PBoolean>;
begin
  result := TArray<PBoolean>.Create(@b1, @b2, @b3);
end;

function GetVarsChar: TArray<PChar>;
begin
  result := TArray<PChar>.Create(@c1);
end;

function GetVarsDateTime: TArray<PDateTime>;
begin
  result := TArray<PDateTime>.Create(@d1, @d2, @d3, @d4);
end;

function GetVarsMyFileStream: TArray<PMyFileStream>;
begin
  result := TArray<PMyFileStream>.Create(@f1, @f2, @f3, @f4, @f5, @f6, @f7, @f8);
end;

procedure HandleInt(var Value: Integer);
begin

end;

procedure HandleBool(var Value: Boolean);
begin

end;

procedure HandleChar(var Value: Char);
begin

end;

procedure HandleDateTime(var Value: TDateTime);
begin

end;

procedure HandleMyFileStream(var Value: TMyFileStream);
begin

end;

procedure MyProc;
var
  vInt: PInteger;
  vBool: PBoolean;
  vChar: PChar;
  vDateTime: PDateTime;
  vMyFileStream: PMyFileStream;
begin
  for vInt in GetVarsInt do
    HandleInt(vInt^);
  for vBool in GetVarsBool do
    HandleBool(vBool^);
  for vChar in GetVarsChar do
    HandleChar(vChar^);
  for vDateTime in GetVarsDateTime do
    HandleDateTime(vDateTime^);
  for vMyFileStream in GetVarsMyFileStream do
    HandleMyFileStream(vMyFileStream^);
end;

In case of the TMyFileStream variables, you might get away with no pointers when you only want to manipulate the existing object instances.

Sign up to request clarification or add additional context in comments.

1 Comment

Uwe can make Delphi do amazing (and modern) things. I think of him as the Master of Iteration anyway. :-) But the concept itself shouldn't make anyone shiver: if Delphi had tuples this would have been a lot more straight-forward.
2

If you put these variables in a class you can use RTTI to loop over the properties of that class. There is no method that I know of to loop over variables that do not belong to a class.

1 Comment

You might want to point out that the properties need to be Published or defined with {$M+}/{$TYPEINFO ON}.
0

I've already thought of putting them in an (either static or dynamic) array, but this involves the modifocation of code at every location where they are referenced, which is much-much-much work that I wanna spare if it's possible by any means.

So what! Do it!
The longer you put off fixing horrible code, the worse it will get. Also, it's not nearly as bad as you think.

E.g. Change the following:

var
  a1,a2,a3,a4,a5: integer;

to:

var
  A: array[1..5] of Integer;

Now everything that was referring to a? will fail to compile (unless you had scope conflicts, which would be a simmering pot of disaster in any case). These compilation errors can easily be fixed by changing a? to a[?].

If you simply go through a cycle of: compile --> fix --> compile --> fix --> ... You'll find you can clean up a lot faster than you think.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.