Here's my problem: I want to create a record type where among the cases of a variant record, some, but not all, will have a certain field. According to the wiki, this is perfectly legal. And yet, when I tried to compile the following code:
maritalStates = (single, married, widowed, divorced);
TPerson = record
first, middle, last: string;
sex: (male, female);
case maritalStatus: maritalStates of
single: ( );
married, widowed: (marriageDate: TDateTime);
divorced: (marriageDate, divorceDate: TDateTime;
ExPerson.name.first := 'John';
ExPerson.name.middle := 'Bob';
ExPerson.name.last := 'Smith';
ExPerson.sex := male;
ExPerson.dob := StrToDate('05/05/1990');
ExPerson.maritalStatus := married;
ExPerson.marriageDate := StrToDate('04/01/2015');
$ fpc ex.pas
Free Pascal Compiler version 3.0.0 [2016/02/14] for x86_64
Copyright (c) 1993-2015 by Florian Klaempfl and others
Target OS: Win64 for x64
ex.pas(19,18) Error: Duplicate identifier "marriageDate"
ex.pas(21,3) Error: Duplicate identifier "marriageDate"
ex.pas(35,4) Fatal: There were 2 errors compiling module, stopping
Fatal: Compilation aborted
Error: C:\lazarus\fpc\3.0.0\bin\x86_64-win64\ppcx64.exe returned an error exitcode
Very interesting question. I was sure this is possible. If You modify Your code to:
.. married, widowed, divorced: (marriageDate: TDateTime); divorced: (divorceDate: TDateTime; isFirstDivorce: boolean) ..
it works, but it is not the result you intend to have. Since marriageDate and the divorceDate overlay each other (as mentioned in the comments!)
This picture is taken from "Pascal users manual (4th edition)" and as you can see the variant parts have the same memory location.
- All field names must be distinct - even if they occur in different variants.
- If a variant is empty (i.e., has no fields), the form is: C:()
- A field list can have only one variant part and it must follow the fixed part of the record.
- A variant may itself contain a variant part; hence variant parts can be nested.
- The scope of enumerated type constant identifiers that are introduced in a record type extends over the enclosing block.
Point 1 is the relevant one here! The book "Turbo Pascal" the suggested solution is to use a unique prefix for field names that occur multiple times.
In Your case Your could would look like:
TPerson = record name: record first, middle, last: string; end; sex: (male, female); dob: TDateTime; case maritalStatus: maritalStates of single: ( ); married, widowed: (marMarriageDate: TDateTime); divorced: (divMarriageDate, divorceDate: TDateTime; isFirstDivorce: boolean) end;
The other solution would be to define married, devorced ... as a record type.
.. married : (m: TMarried); divorced : (d: TDivorced); ..