2

Recently I found some odd-looking (to me) Delphi code and I have isolated it to a separate small project. Here is what I discovered. Unit1 compiles with no errors. Unit2 (which I provide for comparison) does not. The difference is in the way that Classes is used.

unit Unit1;

interface

uses Classes; // difference here

type TThread = class(Classes.TThread)
public
   property Terminated;
end;

implementation

end.

Unit2 does not compile. Various errors are produced.

unit Unit2;

interface

uses System.Classes; // difference here

type TThread = class(Classes.TThread)
public
  property Terminated;
end;

implementation

end.

[dcc32 Error] Unit1.pas(7): E2003 Undeclared identifier: 'Classes'
[dcc32 Error] Unit1.pas(7): E2029 ',' or ':' expected but ')' found
[dcc32 Error] Unit1.pas(9): E2147 Property 'Terminated' does not exist in base class

So my concern is that this project is exploiting a compiler bug to achieve it's goals. The compiler bug might be fixed in a later release, and then the code won't work anymore.

dummzeuch
  • 10,975
  • 4
  • 51
  • 158
Freddie Bell
  • 2,186
  • 24
  • 43
  • 2
    Of course it is bad practice to use a compiler bug. But that is not what is going on here. What version of Delphi are you using, and what errors are you getting? – Dsm Feb 19 '18 at 09:20
  • @Dsm. It's Delphi 10.0 and Delphi 10.1 (both, the same) I have edited the question to include the error messages for Unit2. There are no errors for Unit1 and Unit3. – Freddie Bell Feb 19 '18 at 09:26
  • 2
    I cannot see a compiler bug here. The code of Unit2 is just wrong, while the code of Unit1 relies on the correct setting of unit scope names. – Uwe Raabe Feb 19 '18 at 09:28
  • @UweRaabe. In what way is unit2's code wrong? – Freddie Bell Feb 19 '18 at 09:30
  • 7
    @nolaspeaker: if the uses contains the fully qualified `System.Classes`, then it must be used like that in the rest of the unit too, so `Classes.TThread` must be fully qualified as `System.Classes.TThread`. FWIW, I'd rather do something like: `TFetchMessageThread = class(TThread)`. – Rudy Velthuis Feb 19 '18 at 09:40
  • True. The new TThread class really should have a better name. – Freddie Bell Feb 19 '18 at 15:55
  • 1
    Related: https://stackoverflow.com/a/8797352/988445 – Jerry Dodge Feb 20 '18 at 05:40

2 Answers2

11

There is no compiler bug that makes Unit1 compile. It compiles because in the project setting the entry for Unit Scope Names contains at least the item System, which is used to resolve the reference to Classes in the full name System.Classes. As the uses contains Classes, the reference to Classes.TThread also succeeds.

In Unit2 the uses contains System.Classes. Therefore the reference Classes.TThread cannot be resolved anymore. Change it to System.Classes.TThread and it works.

Uwe Raabe
  • 45,288
  • 3
  • 82
  • 130
9

If you uses System.Classes you must also use System.Classes when referring to the classes unit in the code as shown below.

unit Unit2;

interface

uses System.Classes; // difference here

type TThread = class(System.Classes.TThread)
public
  property Terminated;
end;

implementation

end.
Jan Lauridsen
  • 586
  • 4
  • 9