{"id":273,"date":"2008-08-30T13:33:24","date_gmt":"2008-08-30T01:33:24","guid":{"rendered":"https:\/\/www.deltics.co.nz\/blog\/?p=273"},"modified":"2008-08-31T09:37:56","modified_gmt":"2008-08-30T21:37:56","slug":"class-helpers-on-trial","status":"publish","type":"post","link":"https:\/\/www.deltics.co.nz\/blog\/posts\/273\/","title":{"rendered":"Class Helpers On Trial"},"content":{"rendered":"<span class=\"rt-reading-time\" style=\"display: block;\"><span class=\"rt-label rt-prefix\">[Estimated Reading Time: <\/span> <span class=\"rt-time\">5<\/span> <span class=\"rt-label rt-postfix\">minutes]<\/span><\/span><p>Class helpers (introduced in Delphi <span style=\"text-decoration: line-through;\">2007<\/span> <span style=\"text-decoration: line-through;\">2006<\/span> 2005 &#8211; thanks to Chris and Bruce for the corrections) seem to be cropping up more and more frequently in suggested work-arounds or implementation approaches.\u00a0 I find this worrying given that this language feature has always come with the admonition from CodeGear that it isn&#8217;t advisable to use it!<\/p>\n<p>So why do people seem so keen on using them, and why shouldn&#8217;t they?<\/p>\n<p><!--more--><\/p>\n<p>Class helpers are to be considered &#8220;bad&#8221; when used in an application because they were never designed for general purpose use. As I understand it, they were devised to workaround a problem (or problem<em>s<\/em>) in the VCL that existed for the language (or more accurately, the VCL) implementors, not those who implement code that merely <span style=\"text-decoration: underline;\">uses<\/span> the VCL.<\/p>\n<p>The biggest problem with class helpers, from the point of view of using them in your own applications, is the fact that only <em><strong>one<\/strong><\/em> class helper for a given class may be referenced at any time.<\/p>\n<p>That is, if you have two helpers for a class nominally reachable in your code (e.g. in two separate units both of which are in your uses list), only one of them will actually be &#8220;seen&#8221; by the compiler. You won&#8217;t get any warnings or even hints about any other helpers that exist or may be hidden.<\/p>\n<p>So you can be happily coding away with your lovingly crafted helper, and then you add some other unit to your uses list that unbeknownst to you contains another helper for the same class and suddenly your code simply stops compiling.<\/p>\n<p>Since helpers are used &#8211; as designed &#8211; within the VCL, adding your own helpers for VCL classes is likely to lead to this problem if you also write code that (perhaps unknown to you) relies on the VCL helpers for those classes.<\/p>\n<h3>A Sticky Situation<\/h3>\n<p>You may be able to fudge your way out of this predicament by fiddling with the order of your units in the uses list (once you&#8217;ve figured out what&#8217;s going on, which is likely to come after perhaps your 2nd or 3rd restart of the IDE and an experimental reboot or two before you accept that it isn&#8217;t just the compiler having &#8220;a moment&#8221;).<\/p>\n<p>If you can&#8217;t fix it with the uses list &#8211; if more than 2 helpers are involved &#8211; you might perhaps succeed in moving one or other helper up or down the ancestry of the helped class, assuming you are in control of the source for that helper and hoping that that does not in turn create a conflict with some <span style=\"text-decoration: underline;\">other<\/span> helper out there, perhaps in some other area of your code.<\/p>\n<p>But if you can&#8217;t wriggle your way out of the situation then you are well and truly stuck, because you can&#8217;t even use qualification to forcibly reference the &#8220;hidden&#8221; helper.<\/p>\n<pre class=\"delphi\">  TMyHelper(obj).MyMethod;<\/pre>\n<p>Won&#8217;t compile if <strong>TMyHelper<\/strong> is &#8220;hidden&#8221; by some other helper for the class of <strong>obj<\/strong> involved. In fact, this code won&#8217;t compile anyway because <strong>TMyHelper<\/strong> does not exist as a &#8220;proper&#8221; type, so you can&#8217;t even use this style to aid clarity if you wish (i.e. to make it clear that your code is reliant on a helper).<\/p>\n<h3>But Without Class Helpers, What Can We Do?<\/h3>\n<p>Fortunately there is an alternative, which is not only immune from all these problems but is also in my opinion actually more flexible\/powerful (not least because it works in any Delphi version).<\/p>\n<p>That is, to use explicit helper-<em>style<\/em> pseudo sub-classes, the &#8220;old fashioned&#8221; way, where you adhere to the rules for helpers (only accessing public methods, not adding instance data etc etc) but use explicit hard-casting to &#8220;add&#8221; your methods to an instance.<\/p>\n<pre class=\"delphi\">  TMyHelper = class(TForm)\r\n    procedure MyMethod;\r\n  end;\r\n\r\n  TMyHelper(form).MyMethod;<\/pre>\n<p>This is &#8220;better&#8221; to my mind because:<\/p>\n<p style=\"padding-left: 30px;\">a) it is explicit. No magic. No wondering where these undocumented methods came from (for the uninitiated, unaware of the existence of your &#8220;helper&#8221; class in some obscure unit somewhere).<\/p>\n<p style=\"padding-left: 30px;\">b) it is unbreakable. As long as you stick to the rules for implementing the helper itself, nobody else&#8217;s helper can &#8220;hide&#8221; yours or interfere with how it works.<\/p>\n<p style=\"padding-left: 30px;\">c) it is more powerful and more flexible &#8211; the &#8220;helper&#8221; subclass is able to access <em>protected<\/em> as well as <em>public<\/em> members.<\/p>\n<p>There are three downsides &#8211; two of which are arguably in fact a further benefit, in some situations at least.<\/p>\n<p style=\"padding-left: 30px;\">1) it is necessary to explicitly type-cast in order to invoke your helper functionality.<\/p>\n<p style=\"padding-left: 30px;\">2) the compiler will not prevent you from violating <em>some<\/em> of the rules of class helping (not overriding inherited methods).\u00a0 It still isn&#8217;t possible to access private members, for example.<\/p>\n<p style=\"padding-left: 30px;\">3) protected members are made visible in &#8220;consumer&#8221; code.<\/p>\n<p>It is the first and last of these that I could be considered further <span style=\"text-decoration: underline;\">benefits<\/span>.<\/p>\n<p>In the case of the first, it is made clear that an instance is being treated as something that, strictly speaking, it isn&#8217;t.\u00a0 To my mind the real basis for this complaint is that it involves a little more typing than using a formal helper.<\/p>\n<p>In the case of the third, gaining access to protected members is quite often the very reason that such a class might have been used in the first place, since some aspects of frameworks &#8211; particularly in the case of the VCL &#8211; keep some members protected that would most usefully be made public.<\/p>\n<p>For example, <strong>TControl<\/strong> introduces the <strong>Color<\/strong> property but only as a protected member, so if you have only a <strong>TControl<\/strong> reference to some control whose <strong>Color<\/strong> you wish to change (or inspect) you need some way to bring that protected member into visibility.  You could have a complicated type checking and type casting sequence (hoping you catch all the relevant sub-classes), or you could use a &#8220;helper&#8221;:<\/p>\n<pre class=\"delphi\">  if ctrl is TEdit then\r\n    TEdit(ctrl).Color := aColor\r\n  else if ctrl is TListbox then\r\n    TListbox(ctrl).Color := aColor\r\n  else....<\/pre>\n<p>versus:<\/p>\n<pre class=\"delphi\">  TControlHelper = class(TControl);\r\n\r\n  TControlHelper(ctrl).Color := aColor;<\/pre>\n<p>Note that this is not even possible with a &#8220;proper&#8221; class helper, so if you are using a &#8220;proper&#8221; class helper you will still need this &#8220;dirty&#8221; alternative to solve this particular problem.<\/p>\n<p>Why not simply consistently use one approach that meets all needs?<\/p>\n<h3>But It&#8217;s Not Type Safe!  TWorld.IsEnding!<\/h3>\n<p>Type safety is a potential concern of course, with the risk that you may cast to a helper class inappropriate to the object being cast, but this is not a problem unique to class helpers and you can easily code safely with this technique if you prefer:<\/p>\n<pre class=\"delphi\">  TControlHelper(obj as TControl).Color := aColor;<\/pre>\n<p>Personally I feel the slight risk (which it is in my power to mitigate and avoid) is worth the comfort of knowing that some-one else&#8217;s helper (or perhaps even an ill considered additional helper of my own) is not one day going to break my code.<\/p>\n<h3>So Why Bother WIth Class Helpers At All?<\/h3>\n<p>Good question.   It is rather curious that the VCL problem was not solved using this alternate approach, for example.  Why spend time implementing a seemingly flawed language feature to solve an problem that can be easily solved some other way?<\/p>\n<p>I suspect that class helpers might be earmarked for future things&#8230; they bear an uncanny resemblance to extension methods in C#, for example, which are key to the syntactic candy floss and lexical gymnastics required to deliver LINQ.<\/p>\n<p>But until their purpose is fully realised, I personally think it wise to take heed of CodeGear&#8217;s advice and steer well clear.<\/p>\n","protected":false},"excerpt":{"rendered":"<p><span class=\"rt-reading-time\" style=\"display: block;\"><span class=\"rt-label rt-prefix\">[Estimated Reading Time: <\/span> <span class=\"rt-time\">5<\/span> <span class=\"rt-label rt-postfix\">minutes]<\/span><\/span> Class helpers (introduced in Delphi 2007 2006 2005 &#8211; thanks to Chris and Bruce for the corrections) seem to be cropping up more and more frequently in suggested work-arounds or implementation approaches.\u00a0 I find this worrying given that this language feature has always come with the admonition from CodeGear that it isn&#8217;t advisable to use [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"jetpack_publicize_message":"","jetpack_is_tweetstorm":false,"jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":[]},"categories":[4],"tags":[52,292,53],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p1TKYv-4p","jetpack_sharing_enabled":true,"jetpack-related-posts":[{"id":282,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/282\/","url_meta":{"origin":273,"position":0},"title":"Class Helpers &#8211; Ruling from the Appellate Court","date":"01 Sep 2008","format":false,"excerpt":"My previous post on class helpers provoked a passionate response from some quarters who believed that they could be used \"safely\".\u00a0 More worrying was an apparent belief that their use was actually endorsed by CodeGear - tacitly or otherwise.\u00a0 A rather odd view given the advice from CodeGear themselves is\u2026","rel":"","context":"In &quot;Delphi&quot;","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":1938,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/1938\/","url_meta":{"origin":273,"position":1},"title":"Menu Items, APIs, Crackers and Hackers","date":"16 Oct 2013","format":false,"excerpt":"Francois Piette recently posted a solution to obtaining the screen position of a menu item involving using a \"hacker\" class. There is however a safer, more direct mechanism which I hope Francois won't mind me sharing and a far less safe related hacking technique that his post brought to mind.\u2026","rel":"","context":"In &quot;Delphi&quot;","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":222,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/222\/","url_meta":{"origin":273,"position":2},"title":"More Deltics.Forms Magic","date":"24 Aug 2008","format":false,"excerpt":"Last time I introduced a bit of skullduggery with my Deltics.Forms unit as a way to easily \"inject\" a new TForm class into my projects.\u00a0 We used this new class to add public property that we could use to add a size grip control to any form. This time we\u2026","rel":"","context":"In &quot;Delphi&quot;","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":825,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/825\/","url_meta":{"origin":273,"position":3},"title":"Class Helpers &#8211; A Hackers Cloak of Respectability","date":"09 Nov 2011","format":false,"excerpt":"Mat DeLong just posted another great example of when not to abuse class helpers in Delphi (though I should add that he didn't seem to see it that way). :) But you don't need helpers to do what this technique achieves, and in my view you really shouldn't be using\u2026","rel":"","context":"In &quot;Delphi&quot;","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":1207,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/1207\/","url_meta":{"origin":273,"position":4},"title":"Adventures in Syntax: Something Old, Something New etc&#8230;","date":"20 Sep 2012","format":false,"excerpt":"As the post title says, this will be a brief detour through some features of the Pascal language and a presentation of some (theoretical) alternatives that could have been introduced instead. That is, some are real but little known syntax, others are what I think might be preferable to the\u2026","rel":"","context":"In &quot;Delphi&quot;","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":683,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/683\/","url_meta":{"origin":273,"position":5},"title":"Class Helpers: Extending Classes for Context","date":"21 Nov 2010","format":false,"excerpt":"NEWSFLASH: I believe I have found a use for class helpers in the wild! This, even though I have long held the view that class helpers should not be viewed as a general purpose utility. They were designed for a very specific purpose and the authors of the technology themselves\u2026","rel":"","context":"In &quot;Delphi&quot;","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]}],"_links":{"self":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/273"}],"collection":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/comments?post=273"}],"version-history":[{"count":8,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/273\/revisions"}],"predecessor-version":[{"id":279,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/273\/revisions\/279"}],"wp:attachment":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/media?parent=273"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/categories?post=273"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/tags?post=273"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}