I guess that most of you already heart about it. With Delphi XE3 EMBT introduced record helpers for intrinsic types. E.g. Marco Cantu and Nick Hodges already blogged about it.
Just to explain what record helpers for intrinsic types are I will show an example.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
program TestHelper; {$APPTYPE CONSOLE} {$R *.res} type TMyHelper = record helper for string public function MyFunction: Integer; end; { TMyHelper } function TMyHelper.MyFunction: Integer; begin Result := 42; end; var sBuffer: string; begin Writeln(sBuffer.MyFunction); Readln; end. |
As you can see the record helper allows you to write code that looks like calling a method of an intrinsic type instead of calling a function with the intrinsic type as an argument. This strategy is more object oriented and beautifies your code.
In Delphi XE3 EMBT already introduced some beautiful record helpers. The record helper for the string is the most important and powerful one. It has some really useful functions like Length, Equals, Format, IndexOf etc.. You can find it in the unit System.SysUtils.
Certainly you can write your own record helper for different types. You can also write a record helper for a string and write your own methods.
In the case you add your own helper unit to your uses clause and also System.SysUtils, the compiler only sees one record helper. The record helper which you add at last to your uses clause will win. Let’s have a look at an example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
unit MyHelper; interface type TMyHelper = record helper for string public function MyFunction: Integer; end; implementation { TMyHelper } function TMyHelper.MyFunction: Integer; begin Result := 42; end; end. |
With this unit you can replace the original string helper from System.SysUtils:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
program TestHelper; {$APPTYPE CONSOLE} {$R *.res} uses System.SysUtils, MyHelper in 'MyHelper.pas'; var sBuffer: string; begin Writeln(sBuffer.Length); //This line doesn't work any longer Writeln(sBuffer.MyFunction); Readln; end. |
Instead of replacing the original helper it would be nice to derive from it but this is simply not possible. This code doesn’t compile.
1 2 3 |
type TMyHelper = record helper(TStringHelper) for string end; |
Although class helpers can be derived it is not possible for record helpers. I guess it is because records also cannot be derived.
This issue means that it is nearly impossible to extend the original record helpers. IMO it must be fixed with the next Delphi version.
Anyway, currently I can imagine only one strategy to extend the original record helpers. You have to write you own helper, you have to add all functions of the original one and then you have to call the original function inside your function. And don’t forget to declare them inline because of performance. Since your helper replaces the original one you have to write a call unit for the original helper.
Let’s have a look at an example. First write the caller unit:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
unit MyStringCaller; interface type TMyStringCaller = record public class function ToUpper(const S: string): string; static; inline; end; implementation uses System.SysUtils; { TMyStringCaller } class function TMyStringCaller.ToUpper(const S: string): string; begin Result := S.ToUpper; end; end. |
And then your own record helper:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
unit MyHelper; interface uses System.SysUtils, MyStringCaller; type TMyHelper = record helper for string public function Reverse: string; function ToUpper: string; inline; end; implementation uses System.StrUtils; { TMyHelper } function TMyHelper.Reverse: string; begin Result := ReverseString(Self); end; function TMyHelper.ToUpper: string; begin Result := TMyStringCaller.ToUpper(Self); end; end. |
Last but not least you can use your record helper:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
program TestHelper; {$APPTYPE CONSOLE} {$R *.res} uses System.SysUtils, MyHelper in 'MyHelper.pas'; var sBuffer: string; begin sBuffer := 'Hallo World!'; Writeln(sBuffer.Reverse); Readln; end. |