Question

I've got something that I've never saw before. A local variable that doesn't appear in Local Variables windows when debugging. I'm attaching a image.WHY U NO SHOWN THERE?

As you can see, I'm using the variable in code and optimization is disabled when debugging. But I'm also using generics and anonymous methods, things that I'm not a specialist. The code of the problematic procedure is this (What the procedure does is order the two first arrays ArrayNomes, ArrayValores by length of the string in first array in a desc order):

  procedure OrdenarArrays(var ArrayNomes, ArrayValores: array of string; var ArrayIndices: array of Integer);
  var
    Comparer: IComparer<Integer>;
    I: Integer;
    tmpNomesCampos, tmpValoresCampos: array of String;
  begin

    SetLength(tmpNomesCampos,   cdsCadastro.FieldCount);
    SetLength(tmpValoresCampos, cdsCadastro.FieldCount);

    //Carregar os NomesCampos para serem usados na comparação
    for I := 0 to High(arrayIndices) do
    begin
      tmpNomesCampos[I] := ArrayNomes[I];
    end;

    { Cria novo delegatedcomparer. Ele permite o uso de um callback para comparar os arrays}
    Comparer := TDelegatedComparer<Integer>.Create(
      { TComparison<Integer> }
      function(const Left, Right: Integer): Integer
      begin
        {colocar em ordem decrescente de acordo com o tamanho do nome do campo}
//        Result := Left - Right;
        Result := -(Length(tmpNomesCampos[Left]) - Length(tmpNomesCampos[Right]));
      end);

    { Ordena o Array base }
    TArray.Sort<Integer>(arrayIndices, Comparer);

    //Reordenar os NomesCampos de acordo com o array IndicesCampos
    for I := 0 to High(arrayIndices) do
    begin
      tmpNomesCampos[I]   := ArrayNomes[arrayIndices[I]];
      tmpValoresCampos[I] := ArrayValores[arrayIndices[I]];
    end;

    //Salvar nos arrays definitivos;
    for I := 0 to High(arrayIndices) do
    begin
      ArrayNomes[I]   := tmpNomesCampos[I];
      ArrayValores[I] := tmpValoresCampos[I];
    end;

  end;

Is this variable not showing a bug? Is it an already known bug? Or could it be a feature on using generics and anonymous methods that I don't know?

System: Windows 7 64 bits/Delphi XE (latest updates)


UPDATE: Changed the code to a simplified console version below. This may help anyone who want to test in his Delphi version. Note: It doesn't fill the original arrays, because it is not necessary to show the issue;

program Project1;


{$APPTYPE CONSOLE}

uses
  SysUtils, Generics.Collections, Generics.Defaults;

  procedure OrdenarArrays(var ArrayNomes, ArrayValores: array of string; var ArrayIndices: array of Integer);
  var
    Comparer: IComparer<Integer>;
    I: Integer;
    tmpNomesCampos, tmpValoresCampos: array of String;
  begin

    SetLength(tmpNomesCampos,   Length(arrayIndices));
    SetLength(tmpValoresCampos, Length(arrayIndices));

    //Carregar os NomesCampos para serem usados na comparação
    for I := 0 to High(arrayIndices) do
    begin
      tmpNomesCampos[I] := ArrayNomes[I];
    end;

    { Cria novo delegatedcomparer. Ele permite o uso de um callback para comparar os arrays}
    Comparer := TDelegatedComparer<Integer>.Create(
      { TComparison<Integer> }
      function(const Left, Right: Integer): Integer
      begin
        {colocar em ordem decrescente de acordo com o tamanho do nome do campo}
  //        Result := Left - Right;
        Result := -(Length(tmpNomesCampos[Left]) - Length(tmpNomesCampos[Right]));
      end);

    { Ordena o Array base }
    TArray.Sort<Integer>(arrayIndices, Comparer);

    //Reordenar os NomesCampos de acordo com o array IndicesCampos
    for I := 0 to High(arrayIndices) do
    begin
      tmpNomesCampos[I]   := ArrayNomes[arrayIndices[I]];
      tmpValoresCampos[I] := ArrayValores[arrayIndices[I]];
    end;

    //Salvar nos arrays definitivos;
    for I := 0 to High(arrayIndices) do
    begin
      ArrayNomes[I]   := tmpNomesCampos[I];
      ArrayValores[I] := tmpValoresCampos[I];
    end;

  end;

var
  NomesCampos, ValoresCampos: array of String;
  IndicesCampos: array of Integer;
  I: Integer;
begin
  try

    SetLength(NomesCampos,   42);
    SetLength(ValoresCampos, 42);
    SetLength(IndicesCampos, 42);

//    for I := 0 to 41 do

    OrdenarArrays(NomesCampos, ValoresCampos, IndicesCampos);

    Readln;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.
Was it helpful?

Solution

This is a debugger/IDE bug that is still present in XE5. The problem is, as you suspected, related to the use of anonymous methods. The key is whether or not a variable is captured. When a variable is captured, that variable does not show up in the Locals window. Here is the shortest SSCCE that I can concoct:

{$APPTYPE CONSOLE}

uses
  System.SysUtils;

procedure Foo1;
var
  func: TFunc<Integer>;
  val: Integer;
begin
  val := 666;
  func :=
    function: Integer
    begin
      Result := val;
    end;
end;

procedure Foo2;
var
  func: TFunc<Integer>;
  val: Integer;
begin
  val := 666;
  func :=
    function: Integer
    begin
      Result := 666;
    end;
end;

begin
  Foo1;
  Foo2;
  Readln;
end.

In the debugger, Foo1.val does not show up in the Locals window. But Foo2.val does.

QC#121821

OTHER TIPS

Not an answer to the question but a suggestion on how to write the routine in a much simpler way (at least if I understood what it should do)

procedure OrderArrays(var ArrayNameValuePairs: array of TPair<string, string>);
begin
  TArray.Sort<TPair<string, string>>(ArrayNameValuePairs,
    TComparer<TPair<string, string>>.Construct(
      function(const Left, Right: TPair<string, string>): Integer
      begin
        Result := Length(Right.Key) - Length(Left.Key);
      end));
end;

As you can see I combined names and values as they obviously belong together. This makes sorting this combined array much easier as you do not have to sort a third array holding the indizes to reorder the two original arrays.

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