Reputation: 1777
I have 10 double variables I would like to initialize with the value 0. They are unstructured and not part of an array by design.
procedure Initialize;
var
a1, a2, a3, a4, a5, b1, b2, b3, b4, b5: Double;
begin
a1 := 0;
a2 := 0;
a3 := 0;
a4 := 0;
a5 := 0;
b1 := 0;
b2 := 0;
b3 := 0;
b4 := 0;
b5 := 0;
end;
To refactor that piece of code, I'm introducing a helper method AssignValue.
procedure Initialize;
var
a1, a2, a3, a4, a5, b1, b2, b3, b4, b5: Double;
begin
AssignValue(0,a1);
AssignValue(0,a2);
...
end;
procedure AssignValue(value: Double; var target: Double);
begin
target:= value;
end;
How do I write a more general AssignValue
procedure that takes an arbitrary number of arguments and make the call AssignValue(0,a1,a2,a3,a4,a5,b1,b2,b3,b4,b5)
possible?
Bonus question: How do you write that procedure so that it takes into account double
or int
reference in any order, assuming value: Int
as first parameter.
Upvotes: 0
Views: 223
Reputation: 43023
First of all, you can use a record and call fillchar(myrecord,sizeof(myrecord),0)
but it may be error prone if you have some internal reference-counted values (like string
).
But in your case, since it is only double
values, it may be very easy to write:
procedure Initialize;
var localdata: record
a1, a2, a3, a4, a5, b1, b2, b3, b4, b5: Double;
obj: TObject;
i1, i2, i3, i4: integer;
end;
begin
fillchar(localdata,sizeof(localdata),0);
with localdata do
begin
a1 := 10;
a2 := a1+10;
assert(obj=nil);
inc(i1,20);
i2 := i1+10;
assert(i2=30);
end;
end;
As you can see, you can even mix types within the record. The trick is that you define your record type inline, without any type definition, which is not needed.
I admit this is not the direct answer, but I humbly suggest that you change your design to switch to something more "OOP-compatible".
Just use a dynamic array, or a class to embed the values. They will be all set to 0 by default.
For a dynamic array:
var a,b: array of double;
SetLength(a,5); // then use a[0] instead of a1, a[2] instead of a2...
SetLength(b,5); // then use b[0] instead of b1, b[2] instead of b2...
For a class - which is my preferred, since you can embedd your code within your data, as good objects:
type
TMyClass = class
public
a1, a2, a3, a4, a5, b1, b2, b3, b4, b5: Double;
procedure OneMethodHere;
function OneTestHere(aValue: double): boolean;
end;
var C: TMyClass;
C := TMyClass.Create; // every C member will be set to 0
try
if C.OneTestHere(10) then
C.OneMethodHere;
// you can use C.a1 or C.b5
finally
C.Free;
end;
Upvotes: 0
Reputation: 612794
You could do it like this:
procedure AssignValue(const Value: Double; const Addresses: array of PDouble);
var
i: Integer;
begin
for i := low(Addresses) to high(Addresses) do
Addresses[i]^ := Value;
end;
Call it like this:
AssignValue(0.0, [@a1, @a2, @a3, ...]);
Here we are passing an open array containing the addresses of your variables.
To support multiple types you would use overloads declared like this:
procedure AssignValue(const Value: Double; const Addresses: array of PDouble);
overload;
procedure AssignValue(const Value: Integer; const Addresses: array of PInteger);
overload;
// and so on, implementation of these functions is obvious
It's up to you to judge whether or not this is any better than your current solution. Personally, I'd stick with the plain old assignment operator. Another option would be to put the variables inside a record and assign Default(TMyRecord)
to your record variable.
Upvotes: 7
Reputation: 3432
You can use open array parameters for this:
procedure AssignValue(value: double; const arr: array of PDouble);
var
i: Integer;
begin
for i := 0 to length(arr)-1 do
PDouble(arr[i])^ := value;
end;
use it like this (i don't see the way to avoid of "@" for such task):
AssignValue(1, [@a1,@a2,@a3]);
Upvotes: 2