[lazarus] implementation

Marc Weustink weus at quicknet.nl
Wed Apr 26 18:12:31 EDT 2000

At 12:25 26-04-2000 -0700, dvortex wrote:

>Can i do something like this:
>Object1 = record
>   MasterValue : MasterType
>    case Mastervalue
>    mv1:  SubValue: Boolean;
>    mv2:  SubValue: Integer;
>    else: subvalue: TObject;
>   Function GetValueAsString: String;
>can a record have a "case" for its properties ? (i beleive it does, i just
>want confirmation of it)

As far as I know the case you've given is not possible.

Look at the delphi help how TVarRec is constructed.

Your case (functions are not allowed):

   TMasterType = (mv1, mv2, mv3);

   TObject1 = record
      MyFunc: function: Integer;
      case MasterValue: TMasterType of
        mv1:  (SVBool: Boolean);
        mv2:  (SVInt: Integer);
        mv3:  (SVObject: TObject);


   TObject1 = record
      MyFunc: function: Integer;
      MasterValue: TMasterType;
      case TMasterType of
        mv1:  (SVBool: Boolean);
        mv2:  (SVInt: Integer);
        mv3:  (SVObject: TObject);


both cases are AFAIK the same. The value mv1..mv3 doesn't care, it are just 

See the FPC reference guide page 32 and further

Or from the Delphi help:

Variant parts in records

A record type can have a variant part, which looks like a case statement. 
The variant part must follow the other fields in the record declaration.
To declare a record type with a variant part, use the following syntax.

type recordTypeName = record

   fieldList1: type1;
   fieldListn: typen;
case tag: ordinalType of
   constantList1: (variant1);
   constantListn: (variantn);

The first part of the declaration—up to the reserved word case—is the same 
as that of a standard record type. The remainder of the declaration—from 
case to the optional final semicolon—is called the variant part. In the 
variant part,

tag is optional and can be any valid identifier. If you omit tag, omit the 
colon (:) after it as well.
         ordinalType denotes an ordinal type.
         Each constantList is a constant denoting a value of type 
ordinalType, or a comma-delimited list of such constants. No value can be 
represented more than once in the combined constantLists.
         Each variant is a comma-delimited list of declarations resembling 
the fieldList: type constructions in the main part of the record type. That 
is, a variant has the form

fieldList1: type1;

fieldListn: typen;

where each fieldList is a valid identifier or comma-delimited list of 
identifiers, each type denotes a type, and the final semicolon is optional. 
The types must not be long strings, dynamic arrays, variants (that is, 
Variant types), or interfaces, nor can they be structured types that 
contain long strings, dynamic arrays, variants, or interfaces; but they can 
be pointers to these types.

Records with variant parts are complicated syntactically but deceptively 
simple semantically. The variant part of a record contains several variants 
which share the same space in memory. You can read or write to any field of 
any variant at any time; but if you write to a field in one variant and 
then to a field in another variant, you may be overwriting your own data. 
The tag, if there is one, functions as an extra field (of type ordinalType) 
in the non-variant part of the record.

Variant parts have two purposes. First, suppose you want to create a record 
type that has fields for different kinds of data, but you know that you 
will never need to use all of the fields in a single record instance. For 


   TEmployee = record
   FirstName, LastName: string[40];
   BirthDate: TDate;
   case Salaried: Boolean of
     True: (AnnualSalary: Currency);
     False: (HourlyWage: Currency);

The idea here is that every employee has either a salary or an hourly wage, 
but not both. So when you create an instance of TEmployee, there is no 
reason to allocate enough memory for both fields. In this case, the only 
difference between the variants is in the field names, but the fields could 
just as easily have been of different types. Consider some more complicated 


   TPerson = record
   FirstName, LastName: string[40];
   BirthDate: TDate;
   case Citizen: Boolean of
     True: (Birthplace: string[40]);
     False: (Country: string[20];
             EntryPort: string[20];
             EntryDate, ExitDate: TDate);


   TShapeList = (Rectangle, Triangle, Circle, Ellipse, Other);
   TFigure = record
     case TShapeList of
       Rectangle: (Height, Width: Real);
       Triangle: (Side1, Side2, Angle: Real);
       Circle: (Radius: Real);
       Ellipse, Other: ();

For each record instance, the compiler allocates enough memory to hold all 
the fields in the largest variant. The optional tag and the constantLists 
(like Rectangle, Triangle, and so forth in the last example above) play no 
role in the way the compiler manages the fields; they are there only for 
the convenience of the programmer.
The second reason for variant parts is that they let you treat the same 
data as belonging to different types, even in cases where the compiler 
would not allow a typecast. For example, if you have a 64-bit Real as the 
first field in one variant and a 32-bit Integer as the first field in 
another, you can assign a value to the Real field and then read back the 
first 32 bits of it as the value of the Integer field (passing it, say, to 
a function that requires integer parameters).

More information about the Lazarus mailing list