Records
From The Oxygene Language Wiki
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
Area: Oxygene Language
Compiler version: Oxygene 5
Language Glossary — Keywords — Types — FAQ — How To