2

I have following code (simplified):

program Project1;

{$APPTYPE CONSOLE}

uses
  SysUtils,
  Unit1 in 'Unit1.pas';

var
  f: TFoo<Integer>;
begin
  f := TFoo<Integer>.Create;
  f.Baz;
  Readln;
end.


unit Unit1;

{$D-}

interface

type
  TFoo = class
  public
    procedure Bar(const s: string);
  end;

  TFoo<T> = class(TFoo)
  public
    procedure Baz;
  end;

implementation

uses
  TypInfo;

{ TFoo }

procedure TFoo.Bar(const s: string);
begin
  Writeln(s);
end;

{ TFoo<T> }

procedure TFoo<T>.Baz;
begin
  Bar(PTypeInfo(TypeInfo(T)).Name);
end;

end.

Now when stepping into f.Baz I always end up in Unit1.TFoo<T>.Baz although I explicitly disabled debug info for that unit but I cannot step into TFoo.Bar which is correct. I think this is because of how generics internally are implemented (like templates) and because TFoo<Integer> is defined in my Project1. When I add following unit I cannot step into Baz anymore:

unit Unit2;

{$D-}

interface

uses
  Unit1;

type
  TIntegerFoo = TFoo<Integer>;

implementation

end.

Now is there any way to remove debug info for a generic type altogether so I can specialize that type anywhere (where debug info is on) but avoid stepping into the methods of the generic type? I guess it must be possible since I cannot step info any Generics.Collections.TList<T> method without enabling the "use debug .dcus" option.

Stefan Glienke
  • 20,860
  • 2
  • 48
  • 102
  • What did you expect? You did not the same, because on compilation your unit will get compiled into a dcu and then get linked. But System.Generics.Collections will not recompiled, instead the existing dcu will get linked. Depending on compiler settings with or without debug info. Do the same and you will get the same behavior ;o) – Sir Rufo Dec 11 '12 at 17:45
  • Did you try to move the generic part of unit1 into a separate unit? See [Generic defined in unit breaking debug information](http://stackoverflow.com/q/3920434/576719). – LU RD Dec 11 '12 at 18:25
  • Never mind, tried that, no change. – LU RD Dec 11 '12 at 18:48
  • @SirRufo When I compile Unit1 without debug info and use it without any access to the source I still can debug into the Baz method. – Stefan Glienke Dec 12 '12 at 06:50

1 Answers1

3

After a little experimentation, it seems that the determination of whether or not debug info is enabled is controlled by the first unit that references a specific instantiation of the type.

So, if the first time the compiler encounters an instantiation of the type, debug info is enabled, then the specific type will be compiled with debug info. On the other hand, if the first instantiation is in a unit with no debug info, then there will be no debug info.

In your example, the first (and only) instantiation of TFoo<Integer> is in the .dpr file which does have debug info enabled. So, if you move the {$D-} into the .dpr file, and set {$D+} in Unit1, you will find that there is no debug info for TFoo<Integer>.Baz.

The reason I talk about the first instantiation is that there may be many different units that instantiate TFoo<Integer>. The first one that the compiler meets is the one that determines whether or not the instantiated type is compiled with debug info.

It is possible to arrange for TFoo<Integer> to have debug info, but for TFoo<string> not to have debug info.


I guess it must be possible since I cannot step info any Generics.Collections.TList method without enabling the "use debug .dcus" option.

I cannot explain that. According to my hypothesis, debug info should be available for TList instantiations, if debug info is on when you instantiate the class for the first time.

I suspect that there may be a bug in the debugger. For example, I wrote the following program:

{$APPTYPE CONSOLE}
uses
  Generics.Collections;
begin
  TList<Integer>.Create.Add(6);
end.

When I run this with Enable Debug DCUs off, I can indeed step into Generics.Collections. But I step into completely the wrong place. It lands at TList<T>.Pack.

So, I'm sorry I can't offer more insight, but this aspect of your question has me baffled.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • Well, - wehre the code is compilked - there $D+/$D- value is effecting the output. it is what must have been expected. – Arioch 'The Dec 11 '12 at 13:26
  • While I understand your explanations I don't understand why I don't see that behavior when using TList. Shouldn't I also step into the methods there? – Stefan Glienke Dec 11 '12 at 15:15
  • When I compile your example code with debug info on in Delphi XE I cannot debug into any TList method. – Stefan Glienke Dec 12 '12 at 06:55
  • I'm on XE3. On XE2 I see the same as you describe. – David Heffernan Dec 12 '12 at 07:16
  • Maybe on prior versions $D+ should be in effect in BOTH places, both AST creation (declaration of generic) and code creation (instancating concrete types with bound type-parameters) ? And if declaration was with $D- then instantiation would not have it anyway? – Arioch 'The Dec 12 '12 at 10:18
  • @Arioch'The Thing is that I cannot reproduce the behavior I see with Generics.Collections.TList with my own unit in XE (don't know about XE2 and XE3 but as I understand David is also seeing different behavior there) – Stefan Glienke Dec 12 '12 at 12:53