A blog entry from Raymond Chen today made me realize the elegant solution to a problem i’m having.
Various shell functions, rather than all taking ITEMIDLIST structure, can be made to only accept:
ITEMID_CHILDIDLIST_RELATIVEIDLIST_ABSOLUTEITEMID_CHILD_ARRAY
structures. The structures are all identical, but now you can enforce conceptual types at the compiler level.
Back to Delphi
i have a set of functions:
- some only take a path: (e.g.
C:\Users\Ian\Desktop\AllisonAngel.jpg) - some only take a filename: (e.g.
AllisonAngel.jpg) - some only take a folder: (e.g.
C:\Users\Ian\Desktop)
And right now they’re all declared as string, e.g.:
function GetFilenames(Folder: string; ...): ...
function IsValidBatchFilename(Path: string): ...
function GetReportType(Filename: string): ...
and i have to trust that i’m passing the right stuff; and i’m trusting that developers (e.g. me), know the difference between:
- a path
- a filename
- and a folder
i want to change the functions to use “typed” strings:
function GetFilenames(Folder: TFolderOnly; ...): ...
function IsValidBatchFilename(Path: TFullPath): ...
function GetReportType(Filename: TFilenameOnly): ...
Where:
type
TFullPath = type string;
TFolderOnly = type string;
TFilenameOnly = type string;
Except that there’s no actual typing happening:
var
dropFolder: string;
begin
dropFolder := GetDropFolderPath(LCT);
GetFilenames(dropFolder); <-- no compile error
end;
What i want is a “distinct” type of string; that is string insofar that it is length prefixed, reference counted, null terminated.
You can use advanced records to accomplish this. For instance, you could do
and similarly for
TPathandTFolder. Advantages:TPathwill not accept aTFileName(or some other combination).TPathto/from a regular string. If you cast from a string to aTPath, you will automatically check the string to see if it contains a valid path.TPathcan be assigned to aTFileName(or some other combination), by writing moreImplicitclass operators.