{"id":121,"date":"2012-11-30T01:27:29","date_gmt":"2012-11-30T00:27:29","guid":{"rendered":"http:\/\/blog.kassebaum.eu\/?p=121"},"modified":"2013-04-25T07:54:55","modified_gmt":"2013-04-25T05:54:55","slug":"record-helpers-for-intrinsic-types","status":"publish","type":"post","link":"https:\/\/www.kassebaum.eu\/blog\/2012\/11\/30\/record-helpers-for-intrinsic-types\/","title":{"rendered":"Record Helpers for Intrinsic Types"},"content":{"rendered":"<p>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. <\/p>\n<p>Just to explain what record helpers for intrinsic types are I will show an example.<\/p>\n<pre class=\"lang:delphi decode:true \" title=\"Example for a string helper\" >\r\nprogram TestHelper;\r\n\r\n{$APPTYPE CONSOLE}\r\n\r\n{$R *.res}\r\n\r\ntype\r\n  TMyHelper = record helper for string\r\n  public\r\n    function MyFunction: Integer;\r\n  end;\r\n\r\n{ TMyHelper }\r\n\r\nfunction TMyHelper.MyFunction: Integer;\r\nbegin\r\n  Result := 42;\r\nend;\r\n\r\nvar\r\n  sBuffer: string;\r\n\r\nbegin\r\n  Writeln(sBuffer.MyFunction);\r\n  Readln;\r\nend.<\/pre>\n<p>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.<\/p>\n<p>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.<\/p>\n<p>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.<\/p>\n<p>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&#8217;s have a look at an example:<\/p>\n<pre class=\"lang:delphi decode:true \" title=\"Example of a String Helper\" >unit MyHelper;\r\n\r\ninterface\r\n\r\ntype\r\n  TMyHelper = record helper for string\r\n  public\r\n    function MyFunction: Integer;\r\n  end;\r\n\r\nimplementation\r\n\r\n{ TMyHelper }\r\n\r\nfunction TMyHelper.MyFunction: Integer;\r\nbegin\r\n  Result := 42;\r\nend;\r\n\r\nend.\r\n<\/pre>\n<p>With this unit you can replace the original string helper from System.SysUtils:<\/p>\n<pre class=\"lang:delphi decode:true \" title=\"Replace the original Record Helper\" >program TestHelper;\r\n\r\n{$APPTYPE CONSOLE}\r\n\r\n{$R *.res}\r\n\r\nuses\r\n  System.SysUtils,\r\n  MyHelper in 'MyHelper.pas';\r\n\r\nvar\r\n  sBuffer: string;\r\n\r\nbegin\r\n  Writeln(sBuffer.Length); \/\/This line doesn't work any longer\r\n  Writeln(sBuffer.MyFunction);\r\n  Readln;\r\nend.<\/pre>\n<p>Instead of replacing the original helper it would be nice to derive from it but this is simply not possible. This code doesn&#8217;t compile.<\/p>\n<pre class=\"lang:delphi decode:true \" title=\"Inheritance doesn't work\" >type\r\n  TMyHelper = record helper(TStringHelper) for string\r\n  end;\r\n<\/pre>\n<p>Although class helpers can be derived it is not possible for record helpers. I guess it is because records also cannot be derived. <\/p>\n<p>This issue means that it is nearly impossible to extend the original record helpers. IMO it must be fixed with the next Delphi version.<\/p>\n<p>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&#8217;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. <\/p>\n<p>Let&#8217;s have a look at an example. First write the caller unit:<\/p>\n<pre class=\"lang:delphi decode:true \" title=\"Call Unit\" >unit MyStringCaller;\r\n\r\ninterface\r\n\r\ntype\r\n  TMyStringCaller = record\r\n  public\r\n    class function ToUpper(const S: string): string; static; inline;\r\n  end;\r\n\r\nimplementation\r\n\r\nuses\r\n  System.SysUtils;\r\n\r\n{ TMyStringCaller }\r\n\r\nclass function TMyStringCaller.ToUpper(const S: string): string;\r\nbegin\r\n  Result := S.ToUpper;\r\nend;\r\n\r\nend.<\/pre>\n<p>And then your own record helper:<\/p>\n<pre class=\"lang:delphi decode:true \" title=\"My Record Helper\" >\r\nunit MyHelper;\r\n\r\ninterface\r\n\r\nuses\r\n  System.SysUtils, MyStringCaller;\r\n\r\ntype\r\n  TMyHelper = record helper for string\r\n  public\r\n    function Reverse: string;\r\n    function ToUpper: string; inline;\r\n  end;\r\n\r\nimplementation\r\n\r\nuses\r\n  System.StrUtils;\r\n\r\n{ TMyHelper }\r\n\r\nfunction TMyHelper.Reverse: string;\r\nbegin\r\n  Result := ReverseString(Self);\r\nend;\r\n\r\nfunction TMyHelper.ToUpper: string;\r\nbegin\r\n  Result := TMyStringCaller.ToUpper(Self);\r\nend;\r\n\r\nend.\r\n<\/pre>\n<p>Last but not least you can use your record helper:<\/p>\n<pre class=\"lang:delphi decode:true \" title=\"Use you Own Helper\" >program TestHelper;\r\n\r\n{$APPTYPE CONSOLE}\r\n\r\n{$R *.res}\r\n\r\nuses\r\n  System.SysUtils,\r\n  MyHelper in 'MyHelper.pas';\r\n\r\nvar\r\n  sBuffer: string;\r\n\r\nbegin\r\n  sBuffer := 'Hallo World!';\r\n  Writeln(sBuffer.Reverse);\r\n  Readln;\r\nend.<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>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 &hellip; <a href=\"https:\/\/www.kassebaum.eu\/blog\/2012\/11\/30\/record-helpers-for-intrinsic-types\/\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3],"tags":[5],"class_list":["post-121","post","type-post","status-publish","format-standard","hentry","category-tipsandtricks","tag-delphi"],"_links":{"self":[{"href":"https:\/\/www.kassebaum.eu\/blog\/wp-json\/wp\/v2\/posts\/121","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.kassebaum.eu\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.kassebaum.eu\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.kassebaum.eu\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.kassebaum.eu\/blog\/wp-json\/wp\/v2\/comments?post=121"}],"version-history":[{"count":34,"href":"https:\/\/www.kassebaum.eu\/blog\/wp-json\/wp\/v2\/posts\/121\/revisions"}],"predecessor-version":[{"id":211,"href":"https:\/\/www.kassebaum.eu\/blog\/wp-json\/wp\/v2\/posts\/121\/revisions\/211"}],"wp:attachment":[{"href":"https:\/\/www.kassebaum.eu\/blog\/wp-json\/wp\/v2\/media?parent=121"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.kassebaum.eu\/blog\/wp-json\/wp\/v2\/categories?post=121"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.kassebaum.eu\/blog\/wp-json\/wp\/v2\/tags?post=121"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}