views:

372

answers:

3

Hi, I am helping out my company with some old delphi 7 code.

There is a record declared at the start that is used throughout to store all the data we want outputted.

type
TOutput_Type = record
result: String;
resultoffset: String;
selected: boolean;
resultcategory: integer;
end;

and then an array of this is declared

Output: array of TOutput_Type;

The length is set at the start to a large value, as actual length is unknown.
This array is used all over the place, but unfortunately the value selected is not always set when used.
My problem is I am adding in a summary of the data, but because selected is not set, delphi seems to give it a random true or false status.
Is there a way of setting all instances of selected as true at the start? Seems like a simple enough thing to do, but I'm not a delphi programmer so am unsure if its possible? I know I can go through and add in selected := true every time a new record is made, but I'd like to do it cleanly at the start if possible....
Thanks in advance

A: 

I'd go for the factory method like in the question dcp linked to. Parameterless constructors aren't allowed for records, so you would always have to specify some parameters, which might be annoying if you don't really need them.

If this is all about initializing the content of the large array once at the start you could also use this:

SetLength(Output, MyArbitraryItemCount);
FillChar(Output[0], Length(Output)*SizeOf(TOutput_Type), 1);

Then everything is 1. Including selected :) Of course you could also use a for-loop...

Heinrich Ulbricht
Setting result: String; to Pointer($01010101) is not that great idea.
Alexander
Or any managed type, for that matter.
Ken Bourassa
Doh. Forgot the managed type. Very good point!
Heinrich Ulbricht
+3  A: 

After calling SetLengt for Output variable you must first initiate the new record parts (because new allocated memory isn't defined) in for loop. Something like:

OldLength := Length(Output);
SetLength(Output, NewLength);
for n := OldLength to NewLength -1 do 
  Output[n].selected := True;
GJ
This is not completely correct. SetLength zero-initialize the memory it allocates which makes boolean values false by default.
Ville Krumlinde
Thanks for your suggestion; I tried it and it takes a long time. The problem is the array is set up with a length of 0 (to clear the array), then a length of around 57000 :) takes minutes to process...
James
@VilleK: From Delphi help: "For a long-string or dynamic-array variable, SetLength reallocates the string or array referenced by S to the given length. Existing characters in the string or elements in the array are preserved, but the content of newly allocated space is undefined."
GJ
@James: hmmm minutes? This is very long time! Normaly such a loop with 57000 iterations takes only few ms. Can you show your code?
GJ
@GJNot sure what I had done wrong; after your comment I copied your code and tried again, and it was pretty much instant :) must have typed something incorrectly the first time. Thanks, I'll go with your suggestion now
James
@GJ: Also from Delphi help: "The one exception is when increasing the length of a dynamic array in which the elements are types that must be initialized (strings, Variants, Variant arrays, or records that contain such types). When S is a dynamic array of types that must be initialized, newly allocated space is set to 0 or nil. "
Ville Krumlinde
@VilleK - Which means that all strings, variants and dynamic arrays will be empty/null, but Booleans and integers will be undefined. So result and resultOffset will be OK, but Selected and ResultCategory will be undefined
Gerry
@GJ, @Gerry: "array of TOutput_Type" is a dynamic array. TOutput_Type falls into the "records that contain such types" category so it will be zeroed. If you check the routine DynArraySetLength in System.pas (which is the routine used when calling SetLength) you will see that it always clears allocated memory using a FillChar-call, at least in Delphi 2010. But I agree that using a loop to initialize is a good idea, especially in this case when the desired value is True (non zero).
Ville Krumlinde
+2  A: 

Records, unlike objects, aren't initialized upon creation, so you need to initialize them yourself. Since you're on Delphi 7, you can't use records with methods, so what I'd do is make an initialization function, something like this:

type
  TOutputArray: array of TOutput_Type; 

function CreateOutputArray(length: integer): TOutputArray;
var
  i: integer;
begin
  SetLength(result, MyArbitraryItemCount);
  FillChar(result[0], Length(Output)*SizeOf(TOutput_Type), 0);
  for i := 0 to high(result) do
    result[i].selected := true;
end;
Mason Wheeler
@Mason - slight problem with example - you use Length as a parameter, then try to use Length function. I assume you meant to call parameter MyArbitraryItemCount
Gerry
@Gerry: Yeah, something like that.
Mason Wheeler