Records

From The Oxygene Language Wiki

Jump to:navigation, search

This is a Language topic
Feel free to add your notes to this topic below.



In classical Object Pascal, a record consists of a collection of variables (usually known as fields) that do not support methods.

Delphi Prism records are based upon System.ValueType and therefore support most of the functionality of Classes (but no inheritance).

A simple example:

type
  Person = Record
    Forename, Surname: String;
    Born: Integer;
  end;

This syntax matches that of Object Pascal and so does the use of such records:

var p: Person;
begin
  p.Forename := 'John';
  p.Surname := 'Smith';
  p.Born := 1977;

The ability to provide records with methods makes them far more useful. For example, you can make a record describe itself, which is far better than writing a method. System.ValueType descends from System.Object and thus the latter's toString function is available and we can override it:

type
  Person = Record
  public
    method ToString: String; override;

    Forename,Surname: String;
    Born: Integer;
  end;

A possible implementation of the method is:

implementation
method Person.ToString: String;
begin
  Result := Forename+' '+Surname+', Born '+Born.ToString;
end;

This then allows:

Console.WriteLine(p.toString);

Using the data example above, we see the following:

John Smith, Born 1977.

Record Visibility

In common with other types, the default visibility is assembly, thus you will need to add the public specifier to the record if you require a wider access:

type
  MyRecord = public record
  public
    A: integer;
    B: integer;
  end;


Record Storage Considerations

By default, fields within a record are placed as .NET determines and so they can occupy more storage than you might expect. Classical Object Pascal supplies the packed modifier to remove wasted space (resulting in a minor performance penalty). Delphi Prism provides the same functionality by supporting the StructLayout attribute.

uses System.Runtime.InteropServices;

type
  [StructLayout(LayoutKind.Sequential, Pack := 1)]
  MyRecord = record 
  public
    FieldA: Integer;
    FieldB: Byte;
  end;
...
var
  R: MyRecord;
  Size: Integer;
begin
  Size := SizeOf(MyRecord);
  Console.WriteLine('SizeOf(R) = {0}', Size);
end;

The code above will return 5, but if the first line is removed, it returns 8.


Interface Support

Records can be based on one or more interfaces:

TestRec = Record(IDisposable)
  private
    field1: Integer;
    field2: String;
    field3: byte; 
  public
    method Dispose;
  end;


Unsafe Records

Records containing pointers and address references (^,@) contain unsafe code and need to be flagged as unsafe. Also, the unsafe compiler option must be set.

See Fixed Size Buffers for a description of inline arrays.


Notes

Tip: .NET doesn't support empty (field-less) records and, as such, the following code does not compile:

type 
  MyRecord = record 
  end;

If you need an empty record (for a stack-based unsafe array, for example), you can give it an implicit size like this:

type
  [StructLayout(LayoutKind.Explicit, Size := 1028)]
  MyRecord = record
  end;

A record with methods but no fields is regarded as empty and needs code as seen above.


See Also


Oxygene-48.png

Area: Oxygene Language
Compiler version: Oxygene 5

Language GlossaryKeywordsTypesFAQHow To

Navigation
Areas
More
Toolbox