I’ve been experimenting with the Delphi hinting directives lately to make it easier to migrate some libraries to newer versions of Delphi and newer platforms.
Hinting directives (deprecated, experimental, library and platform) were – like the $MESSAGE directive– added to Delphi 6.
Up to Delphi 5 you didn’t have any means to declare code obsolete. You had to find clever ways around it.
Warnings for hinting directives
When referring to identifiers marked with a hinting directive, you can get various warning messages that depend on the kind of identifier: unit, or other symbol.
Note the warning numbering is not in the alphabetic order of the hinting directive.
Unit identifiers can get these warnings:
- W1006 Unit ‘HintingDirectivesUnit’ is deprecated
//unit HintingDirectivesUnit deprecated; - W1007 Unit ‘HintingDirectivesUnit’ is experimental
//unit HintingDirectivesUnit experimental; - W1004 Unit ‘HintingDirectivesUnit’ is specific to a library
//unit HintingDirectivesUnit library; - W1005 Unit ‘HintingDirectivesUnit’ is specific to a platform
//unit HintingDirectivesUnit platform;
Non-unit symbols can get these warnings:
- W1000 Symbol ‘FieldDepracated’ is deprecated
//Default.FieldDepracated := 1; - W1003 Symbol ‘FieldExperimental’ is experimental
//Default.FieldExperimental := 1; - W1001 Symbol ‘FieldLibrary’ is specific to a library
//Default.FieldLibrary := 1; - W1002 Symbol ‘FieldPlatform’ is specific to a platform
//Default.FieldPlatform := 1;
Hinting directives: deprecated differs from the others
Of the hinting directives, deprecated is more versatile than experimental, library and platform as it allows two forms: with and without a ‘comment’.
I wasn’t aware of this part of the deprecated syntax until recently. The syntax part was introduced in Delphi 12.0 (aka Delphi 2009). You can for instance see it in the RTLConsts unit:
SInvalidDate = '''''%s'''' is not a valid date' deprecated 'Use SysConsts.SInvalidDate';
SInvalidDateTime = '''''%s'''' is not a valid date and time' deprecated 'Use SysConsts.SInvalidDateTime';
SInvalidInteger = '''''%s'''' is not a valid integer value' deprecated 'Use SysConsts.SInvalidInteger';
SInvalidTime = '''''%s'''' is not a valid time' deprecated 'Use SysConsts.SInvalidTime';
STimeEncodeError = 'Invalid argument to time encode' deprecated 'Use SysConsts.STimeEncodeError';ModelMaker Code Explorer does not support this syntax yet, but they are aware of this.
But depending on the kind of identifier you use it on, the compiler warnings can be different.
When used on a unit, you can use both forms, but when using the unit, you get one kind of compiler warning:
//[DCC Warning] HintingDirectivesConsoleProject.dpr(9): W1006 Unit 'HintingDirectivesUnit' is deprecated //unit HintingDirectivesUnit deprecated;
No warning about the ‘comment':
//[DCC Warning] HintingDirectivesConsoleProject.dpr(9): W1006 Unit 'HintingDirectivesUnit' is deprecated //unit HintingDirectivesUnit deprecated 'use a different one';
But when using it on a variable,
var I: Integer deprecated 'do not use global variables'; J: Integer deprecated; K: Integer deprecated platform library experimental;
the forms result in different compiler warnings:
// W1000 Symbol 'I' is deprecated: 'do not use global variables' I := 1; // W1000 Symbol 'J' is deprecated J := 2; // W1000 Symbol 'K' is deprecated // W1001 Symbol 'K' is specific to a library // W1002 Symbol 'K' is specific to a platform // W1003 Symbol 'K' is experimental K := 3;
The effects of a unit hinting directive
The hinting directive documentation states that hinting directives on units apply on references to all the symbols on the unit:
When a hint directive appears in a unit declaration, it means that the hint applies to everything in the unit. For example, the Windows 3.1 style OleAuto.pas unit on Windows is completely deprecated. Any reference to that unit or any symbol in that unit produces a deprecation message.
But this also has a twist on all the unit symbols referenced from within the unit: when a symbol is marked with the same hinting directive as the unit, you will not get a warning referencing that symbol in the unit itself.
So a symbol marked deprecated, will not show a warning when referenced from inside the unit if the unit is also marked deprecated. The same holds for the other hinting directives.
Hinting directives on properties are still a no-go
Despite QC96350 (Cannot apply ‘deprecated’ keyword to property declarations) being open for 2 years, and the StackOverflow question How can I mark a property as deprecated in delphi? you can’t use hinting directives on properties.
So far for consistency (I will blog more on that later).
You cannot do either of these:
type TTest = class protected FValue: Integer; public property Value: Integer read FValue write FValue; deprecated; // E2169 Field definition not allowed after methods or properties property Value2: Integer read FValue write FValue deprecated; // E2029 ';' expected but identifier 'deprecated' found end;
Applying and combining hinting directives
A few rules for using hinting directives
- The semicolon between the hinting directive and the symbol declaration usually has to be left out, except for methods where it has to be there.
- There is no semicolon between combined hinting directives.
- The abstract directive comes after the last hinting directive and does get separated by a semicolon.
So you get code like this:
THinted = class end deprecated platform library experimental; FieldDepracated: Integer deprecated; FieldAll: Integer deprecated platform library experimental; function Func: Integer; virtual; abstract; function FuncDeprecated: Integer; virtual; deprecated; abstract; procedure Proc; virtual; abstract; procedure ProcDeprecated virtual; deprecated; abstract;
Full sample code
The full sample code is a BeSharp SVN change-set; the main unit is below.
Have fun with it!
–jeroen
unit HintingDirectivesUnit; //[DCC Warning] HintingDirectivesConsoleProject.dpr(9): W1006 Unit 'HintingDirectivesUnit' is deprecated //unit HintingDirectivesUnit deprecated; //[DCC Warning] HintingDirectivesConsoleProject.dpr(9): W1007 Unit 'HintingDirectivesUnit' is experimental //unit HintingDirectivesUnit experimental; //[DCC Warning] HintingDirectivesConsoleProject.dpr(9): W1004 Unit 'HintingDirectivesUnit' is specific to a library //unit HintingDirectivesUnit library; //[DCC Warning] HintingDirectivesConsoleProject.dpr(9): W1005 Unit 'HintingDirectivesUnit' is specific to a platform //unit HintingDirectivesUnit platform; //[DCC Warning] HintingDirectivesConsoleProject.dpr(9): W1006 Unit 'HintingDirectivesUnit' is deprecated //unit HintingDirectivesUnit deprecated 'use a different one'; interface var I: Integer deprecated 'do not use global variables'; J: Integer deprecated; K: Integer deprecated platform library experimental; type THinted = class end deprecated platform library experimental; // W1000 Symbol 'THinted' is deprecated // W1001 Symbol 'THinted' is specific to a library // W1002 Symbol 'THinted' is specific to a platform // W1003 Symbol 'THinted' is experimental // W1000 Symbol 'THinted' is deprecated THintedClass = class of THinted; TDefault = class(TObject) strict private FMember: Integer; public Field: Integer; FieldDepracated: Integer deprecated; FieldExperimental: Integer experimental; FieldLibrary: Integer library; FieldPlatform: Integer platform; FieldAll: Integer deprecated platform library experimental; function Func: Integer; virtual; abstract; function FuncDeprecated: Integer; virtual; deprecated; abstract; function FuncExperimental: Integer; virtual; experimental; abstract; function FuncLibrary: Integer; virtual; library; abstract; function FuncPlatform: Integer; virtual; platform; abstract; procedure Proc; virtual; abstract; procedure ProcDeprecated; virtual; deprecated; abstract; procedure ProcExperimental; virtual; experimental; abstract; procedure ProcLibrary; virtual; library; abstract; procedure ProcPlatform; virtual; platform; abstract; property Member: Integer read FMember write FMember; strict protected procedure ProcDeprecatedComment; virtual; deprecated 'use some other Proc in stead'; abstract; strict private // E2169 Field definition not allowed after Procs or properties // procedure ProcAbstractDeprecated; virtual; abstract; deprecated; // E2029 ';' expected but string constant found // procedure ProcExperimentalComment; virtual; experimental 'Experimental Proc'; abstract; // E2029 ';' expected but string constant found // procedure ProcLibraryComment; virtual; library 'Library Proc'; abstract; // E2029 ';' expected but string constant found // procedure ProcPlatformComment; virtual; platform 'Platform Proc'; abstract; // E2169 Field definition not allowed after Procs or properties // property MemberDeprecated: Integer read FMember write FMember; deprecated; end; // W1001 Symbol 'THinted' is specific to a library // W1002 Symbol 'THinted' is specific to a platform // W1003 Symbol 'THinted' is experimental implementation procedure UseDefault; var Default: TDefault; begin // W1000 Symbol 'I' is deprecated: 'do not use global variables' I := 1; // W1000 Symbol 'J' is deprecated J := 2; // W1000 Symbol 'K' is deprecated // W1001 Symbol 'K' is specific to a library // W1002 Symbol 'K' is specific to a platform // W1003 Symbol 'K' is experimental K := 3; // W1000 Symbol 'FuncDeprecated' is deprecated // W1003 Symbol 'FuncExperimental' is experimental // W1001 Symbol 'FuncLibrary' is specific to a library // W1002 Symbol 'FuncPlatform' is specific to a platform // W1000 Symbol 'ProcDeprecated' is deprecated // W1003 Symbol 'ProcExperimental' is experimental // W1001 Symbol 'ProcLibrary' is specific to a library // W1002 Symbol 'ProcPlatform' is specific to a platform // W1000 Symbol 'ProcDeprecatedComment' is deprecated: 'use some other Proc in stead' Default := TDefault.Create(); try Default.Field := 1; // W1000 Symbol 'FieldDepracated' is deprecated Default.FieldDepracated := 1; // W1003 Symbol 'FieldExperimental' is experimental Default.FieldExperimental := 1; // W1001 Symbol 'FieldLibrary' is specific to a library Default.FieldLibrary := 1; // W1002 Symbol 'FieldPlatform' is specific to a platform Default.FieldPlatform := 1; finally Default.Free; end; end; end.
Filed under: Apple Pascal, Borland Pascal, DEC Pascal, Delphi, Delphi 2005, Delphi 2006, Delphi 2007, Delphi 2009, Delphi 2010, Delphi 6, Delphi 7, Delphi 8, Delphi XE, Delphi XE2, Delphi XE3, Delphi XE4, Development, Encoding, FreePascal, ISO-8859, ISO8859, Java, Lazarus, MQ Message Queueing/Queuing, Reflection, Software Development, Sybase, Unicode, UTF-8, UTF8