Question

I want to get the length of a array which is declared as a custom type, and the custom type is declared as an array. I have followed this route to allow me to pass the array as reference.

Here is my code:

type
    TDLLPointerReference = Record
        Pointer  : Pointer;
        IconName : Integer;
        DLLType  : TDLLType;
    end;

type
 TReffArray = array of TDLLPointerReference;

//compressor array's
    PARCompressors : TReffArray;
    PAROnCompressors : TReffArray;
    PARBaseCompressors : TReffArray;
    PARReserveCompressors : TReffArray;
    PARUnavailableCompressors : TReffArray;

function TCompressorPrioritiser.GetCompListLength(Aname : string250): integer;
var
i, k : integer;
begin
    i := ConvertStringtoIndex(AName);   //function to translate comp name to index
    case i of
        0 : k := length(PARCompressors);
        1 : k := length(PAROnCompressors);
        2 : k := length(PARBaseCompressors);
        3 : k := length(PARReserveCompressors);
        4 : k := length(PARUnavailableCompressors);
    else k := 0;
    end;
    result := k;//does not executes

    //test code begin Only added afterward
    PARUnavailableCompressors[1].Pointer := 0;  //executes
    k := length(PARUnavailableCompressors);     //executes
    i := k; //does not executes
    result := 5; //executes
    //test code ends
end;

This function is responsible for the custom type of array.

procedure TCompressorPrioritiser.MoveComp(AIndex : integer; var ACompListOut : TReffArray;var ACompListIn : TReffArray);
var
i : integer;
begin
//This will move a compressor at the index in ACompListOut to  ACompListin
    setlength(ACompListIn, length(ACompListIn)+1);
    ACompListIn[length(ACompListIn)-1] :=  ACompListOut[AIndex];
    For i := Aindex to length(ACompListOut)-2 do
    begin
        ACompListOut[i] := ACompListOut[i+1];
    end;
    setlength(ACompListOut, length(ACompListOut)-1);
end;

Is there any way to perhaps get the array length? Or change the bottom function so I can send the array's through as parameters.

The main problem is that the lines I marked as do not compile, dont seem to run. When I set a breakpoint, those lines of code are just skipped and a breakpoint cannot be set there. Because what I want to do is get the length of the array. The function is suppose to return it, but it skips the return function. Also if a add a watch the the var k, delphi tells me that K is unavailable to to optimization although it was only a line back it was used. The same happens when I add a watch to var i.

I did some further testing. Now the first version of the function every line executes. The second version the line result := k doesn't execute, why is that?

1st version

function TCompressorPrioritiser.GetCompListLength(Aname : string250): integer;
var
i, k : integer;
begin
    i := ConvertStringtoIndex(AName);   //function to translate comp name to index
    case i of
        0 : k := length(PARCompressors);
        1 : k := length(PAROnCompressors);
        2 : k := length(PARBaseCompressors);
        3 : k := length(PARReserveCompressors);
        4 : k := length(PARUnavailableCompressors);
    else k := 0;
    end;
    result := k;//executes

    //test code begin
    k := length(PARUnavailableCompressors);     //executes
    //test code ends
end;

2 version

function TCompressorPrioritiser.GetCompListLength(Aname : string250): integer;
var
i, k : integer;
begin
    i := ConvertStringtoIndex(AName);   //function to translate comp name to index
    case i of
        0 : k := length(PARCompressors);
        1 : k := length(PAROnCompressors);
        2 : k := length(PARBaseCompressors);
        3 : k := length(PARReserveCompressors);
        4 : k := length(PARUnavailableCompressors);
    else k := 0;
    end;
    result := k;//does not executes

    //test code begin
    //k := length(PARUnavailableCompressors);     
    //test code ends
end;

Edit Changed compressor to array. Its a array of references to compressor, didn't type correctly sorry.

Edit2 Added problem statement at the bottom

Edit3 Changed code to reflect code changes recommended. And added secondary part of further testing.

EDIT4

I got the code to work, I get the result I am looking for but I dont get as too why I need the line :"k := length(PARUnavailableCompressors); //executes" It serves no purpose but without that line, the "result :=k" line does not executes. If I replace the K := length line with just K:=6, the result := k line also doesn't execute. So why do I need that other line?

function TCompressorPrioritiser.GetCompListLength(Aname : string250): integer;
var
i, k : integer;
begin
    k := 0;
    i := ConvertStringtoIndex(AName);   //function to translate comp name to index
    case i of
        0 : k := length(PARCompressors);
        1 : k := length(PAROnCompressors);
        2 : k := length(PARBaseCompressors);
        3 : k := length(PARReserveCompressors);
        4 : k := length(PARUnavailableCompressors);
    else k := 0;
    end;
    result := k;
    k := length(PARUnavailableCompressors);     //Withint this line code above line does not execute
    //k :=6;  // this does not have the same effect as the above line
end;
Was it helpful?

Solution

Use Length() to find the length of an array.

The reason that you cannot set breakpoints on the lines that you mark is that the compiler has optimised them away. The compiler has determined that they have no impact.

For instance, you assign one value to Result, and then later assign a different value to Result without reading from Result in the intervening time. Therefore the first assignment is pointless and can be removed.

And the assignment to i is the same. You don't refer to the local variable i in any code that executes after the assignment, and since the assignment has no side-effects it can be removed. The compiler does warn you of this. I hope you have enabled warnings and take notice of them.

Disabling optimization in the compiler options will stop the compiler from excising those lines of code.


Regarding your second update, again the optimizer is confusing you. The compiler has detected that the variable k is superfluous and assigns directly to Result. You can write that function like this:

function TCompressorPrioritiser.GetCompListLength(Aname : string250): integer;
begin
  case ConvertStringtoIndex(AName) of
  0 : Result := length(PARCompressors);
  1 : Result := length(PAROnCompressors);
  2 : Result := length(PARBaseCompressors);
  3 : Result := length(PARReserveCompressors);
  4 : Result := length(PARUnavailableCompressors);
  else Result := 0;
  end;
end;

I must also point out that ACompListOut is incorrectly declared as an out parameter. Since you read it inside the function, it must be declared as var.


I would also suggest that it might be time to stop using short strings and move on to string.

OTHER TIPS

To get the length of an type array, use the Length method:

type
    TTestRecord = record
        Id: Integer;
        Name: String;
    end;

    TTestRecordArray = array of TTestRecord;

...

procedure TForm1.btnTestClick(Sender: TObject);
var
    myArray: TTestRecordArray;
    mySize: Integer;
begin
    SetLength( myArray, 100 );
    ShowMessage( IntToStr( Length( myArray ) ) );
end;

But that's already what you are doing in your MoveComp, so there is something wrong elsewhere. And i := k; compiles when i and k are integer, no matter what, so your debugging logic seems wrong to me...

EDIT >> based on your updated question, your problem is that the Result := k; line seems to be skipped during execution. I would expect this behavior since you have a Result := 5; line after that, so no need for the compiler to bother with your Result := k;. Remove the code between //test code begins and //test code ends, and see what is happening now...

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top