9.1 Definition

Extended records are in many ways equivalent to objects and to a lesser extent to classes: they are records which have methods associated with them, and properties. Like objects, when defined as a variable they are allocated on the stack. They do not need to have a constructor. Extended records have limitations over objects and classes in that they do not allow inheritance and polymorphism. It is impossible to create a descendant record of a record1.

Why then introduce extended records ? They were introduced by Delphi 2005 to support one of the features introduced by .NET. Delphi deprecated the old TP style of objects, and re-introduced the features of .NET as extended records. Free Pascal aims to be Delphi compatible, so extended records are allowed in Free Pascal as well, but only in Delphi mode.

If extended records are desired in ObjFPC mode, then a mode switch must be used:

{$mode objfpc}  
{$modeswitch advancedrecords}

Compatibility is not the only reason for introducing extended records. There are some practical reasons for using methods or properties in records:

  1. It is more in line with an object-oriented approach to programming: the type also contains any methods that work on it.
  2. In contrast with a procedural approach, putting all operations that work on a record in the record itself, allows an IDE to show the available methods on the record when it is displaying code completion options.

Defining an extended record is much like defining an object or class:

_________________________________________________________________________________________________________
extended record type

 --extended- record- type--|---------record--|extended- record- component- list-
                     -packed --        ---------------------------
----end -----------------------------------------------------------

 extended- record-component- list--|---------------------|----------------
                           -record-visibility- specifier-- -|field- definition---
                                                  --------------
----|------------------------|--------------------
    --record- method- definition---- ---property- definition----
-----------------------------         ----------------------------
   --                    --| variant- part
    -record- operator- definition--|

--field-definition- identifier-list- :- type- ;------------------------------

--record- visibility-specifier---|------- private ---------------------------
                      |-strict--        |
                      ------public-------

--                   -|-              --- ----------------------
  record- method- definition  |-confusntrcuticotonr- h- heeaaddeerr-| ;  -call- modifiers ;-|
                      |-procedure- header-|

--                   -     -                   -----------------
  record- operator- definition class  operator- declaration-part
___________________________________________________________________

Some of the restrictions when compared to classes or objects are obvious from the syntax diagram:

Other than that the definition much resembles that of a class or object, except that operators can be defined in an extended record.

As of version 3.2.4 of Free Pascal, extended records can have constructors, on the condition that they have parameters. A parameterless constructor is not allowed.

If no visibility is specified for a record, it is public by default, which is in line with ’classic’ records in which all fields are always visible.

Remark In the case of a variant record, the Case keyword implicitly starts a var section, meaning class variables or methods are not allowed in the variant part of the record.

The following are few examples of valid extended record definitions:

TTest1 = record  
  a : integer;  
  function Test(aRecurse: Boolean): Integer;  
end;  
 
TTest2 = record  
private  
  A,b : integer;  
public  
  procedure setA(AValue : integer);  
  property SafeA : Integer Read A Write SetA;  
end;  
 
TTest3 = packed record  
private  
  fA,fb : byte;  
  procedure setA(AValue : Integer);  
  function geta : integer;  
public  
  property A : Integer Read GetA Write SetA;  
end;  
 
TTest4 = record  
 private  
   a : Integer;  
   function getp : integer;  
 public  
   b : string;  
   procedure setp (aValue : integer);  
   property p : integer read Getp Write SetP;  
 public  
 case x : integer of  
   1 : (Q : string[10]);  
   2 : (S : String[10]);  
 end;

Note that it is possible to specify a visibility for the members of the record. This is particularly useful for example when creating an interface to a C library: the actual fields can be declared hidden, and more “pascal” like properties can be exposed which act as the actual fields. The TTest3 record definition shows that the packed directive can be used in extended records. Extended records have the same memory layout as their regular counterparts: the methods and properties are not part of the record structure in memory.

The TTest4 record definition in the above examples shows that the extended record still has the ability to define a variant part. As with the regular record, the variant part must come last. It cannot contain methods.

1although it can be enhanced using record helpers, more about this in the chapter on record helpers.