Records on Steroids

Another relevant family of value types is represented by structures in C# jargon, or records as they are called in Delphi. If records have always been part of the language, in this version they gain a lot of new ground as records can now have methods associated with them (and even operators, as we'll see later on in this chapter).

A record with methods is somewhat similar to a class: the most relevant difference (beside the lack of inheritance and polymorphisms) is that record type variables use local memory (of the stack frame they are declared onto or the object they are part of), are passed as parameters to functions by value, making a copy, and have a "value copy" behavior on assignments. This contrasts with class type variables that must be allocated on the dynamic memory heap, are passed by references, and have a "reference copy" behavior on assignments (thus copying the reference to the same object in memory).

For example, when you declare a record variable on the stack you can start using it right away, without having to call its constructor. This means record variables are leaner (and more efficient) on the memory manager and garbage collector than regular objects, as they do not participate in the management of the dynamic memory. These are they key reasons for using records instead of object for small and simple data structures.

type

TMyRecord = record private one: string; two: Integer; three: Char; public procedure Print;

constructor Create (aString: string); procedure Init (aValue: Integer); end;

A record can also have a constructor, but the record constructors must have parameters (if you try with Create(); you'll get the error message "Parameterless constructors not allowed on record types". This behavior is far from clear to me, as you still have to manually call the constructor, optionally passing parameters to it (I mean it seems you cannot use the constructor as a type conversion, something you can use the Implicit and Explicit operators for, as discussed later). Here is a sample snippet:

var myrec: TMyRecord; begin myrec := TMyRecord.Create ('hello'); myrec.Print;

Unless there is another way to call a record constructor, for example to initialize a global variable or a field, I'm far from sure why this constructor syntax has been added. Notice, in fact, that using the plain syntax above doesn't affect the initialization portion of the CIL code. In this respect, it seems a better idea to use a plain initialization method rather than a constructor to assign multiple (initial) values to a record structure.

From Borland Object Pascal days, Delphi for .NET has left out the object type definition, which predates Delphi as it was introduced in the days of Turbo Pascal with Objects. The reason is that .NET provides extended records (with methods) that are value types and sit on the stack or in the container type exactly like objects defined with the object keyword in past versions of Delphi. This is another deprecated language feature that few Delphi programmers use, so its absence should not constitute a big roadblock.

Delphi for .NET still allows you to define either a record or a packet record. The difference is traditionally related to 16-bit or 32-bit alignment of the various fields, so that a byte followed by an integer might end up taking up 32 bits even if only 8 are used. The reason is that accessing the following integer value on the 32-bit boundary makes the code faster to execute.

In Delphi for .NET two syntaxes produce structures marked as auto (for a plain record) or sequential (for a packed record). How this data ends up being mapped by the system is probably an implementation specific feature of the CLR so that different platforms can use different approaches. But you can give the CLR a hint...

0 0

Post a comment

  • Receive news updates via email from this site