{"id":282,"date":"2008-09-01T17:06:25","date_gmt":"2008-09-01T05:06:25","guid":{"rendered":"https:\/\/www.deltics.co.nz\/blog\/?p=282"},"modified":"2013-10-16T20:49:39","modified_gmt":"2013-10-16T08:49:39","slug":"class-helpers-ruling-from-the-appellate-court","status":"publish","type":"post","link":"https:\/\/www.deltics.co.nz\/blog\/posts\/282\/","title":{"rendered":"Class Helpers &#8211; Ruling from the Appellate Court"},"content":{"rendered":"<span class=\"rt-reading-time\" style=\"display: block;\"><span class=\"rt-label rt-prefix\">[Estimated Reading Time: <\/span> <span class=\"rt-time\">4<\/span> <span class=\"rt-label rt-postfix\">minutes]<\/span><\/span><p>My previous post on class helpers provoked a passionate response from some quarters who believed that they could be used &#8220;safely&#8221;.&nbsp; More worrying was an apparent belief that their use was actually endorsed by CodeGear &#8211; tacitly or otherwise.&nbsp; A rather odd view given the advice from CodeGear themselves is to not use them.<\/p>\n<p>No-one actually described a safe usage scenario though and those scenarios that <em>were<\/em> described all contained immediately apparent flaws of their own.&nbsp; However, I have realised that there is, if not a safe way then at least a responsible one, to create class helpers.<\/p>\n<p><em>Using<\/em> them is still not entirely safe however.<\/p>\n<p><!--more--><\/p>\n<h3>Scope: The Problem AND The Solution<\/h3>\n<p>The problem that using class helpers creates is caused by the fact that the compiler will only recognise one class helper for a given class at a time.&nbsp; If there are multiple helpers then normal scoping rules apply, and the &#8220;nearest&#8221; helper class is the one that the compiler will accept.&nbsp; Any other helpers do not exist as far as the compiler is concerned.<\/p>\n<p>The potential result is that the simple act of adding a unit to your uses clause can break your code, if that code relies on some helper that is now hidden by the inclusion of that other unit.<\/p>\n<p>Numerous strategies were offered if this should arise, including changing the ancestry of your class helper to extend the other helper, which obviously potentially breaks down if there are more than two helpers involved from different sources.<\/p>\n<p>But the solution lies in the problem itself &#8211; scoping.<\/p>\n<h3>The Devil In The Implementation Detail<\/h3>\n<p>Class helpers are, by definition, an implementation detail of your application code &#8211; they modify a class outside of your direct control to fit the needs\/desires of your code to be able to use a class in a way not supported by the class author, but they have no useful purpose as far as any <em>declarations<\/em> in your code are concerned.<\/p>\n<p>There is absolutely no reason to ever expose a class helper in the interface of a unit &#8211; except of course in a unit that declares and implements a helper, obviously.<\/p>\n<p>By restricting the scope of your class helpers to the tightest possible and requiring helpers to be deliberately and explicitly brought into scope you eliminate the possibility that your helper might accidentally &#8220;collide&#8221; with another helper in someone else&#8217;s code:<\/p>\n<pre class=\"brush: delphi; title: ; notranslate\" title=\"\">\r\nunit MyStreamHelper;\r\n\r\ninterface\r\n\r\n  type\r\n    TStreamHelper = class helper for TStream\r\n      :\r\n    end;\r\n\r\nimplementation\r\n<\/pre>\n<p>As long as <em>everyone<\/em> that uses class helpers sticks to this simple convention of placing helpers in their own unit, then the problem of &#8220;helper hiding&#8221; <em>should<\/em> be largely mitigated.&nbsp; Think of it as the one time when &#8220;one class per unit&#8221; is not just a nice-to-have, but an absolute necessity.<\/p>\n<p>Sadly, even then the solution is not perfect.<\/p>\n<p>Certainly you can be sure that class helpers that <span style=\"text-decoration: underline;\">you<\/span> create will not pose any risk for anybody else, unless they deliberately use your helper <span style=\"text-decoration: underline;\">unit<\/span> themselves in which case one must judge that they know what they are doing.&nbsp; But still, somebody carelessly exposing a class helper in the interface of a unit containing other code that might be more generally useful could still break your code.<\/p>\n<p>Consider for example someone implementing a useful stream class of their own, the implementation of which uses a class helper for <strong>TStream<\/strong> itself to aid the implementation of their specialised stream class <em>and <\/em>which they use in other units in their library or framework which they have shared with you:<\/p>\n<pre class=\"brush: delphi; title: ; notranslate\" title=\"\">\r\n\r\n  unit SpecialisedStream;\r\n\r\ninterface\r\n\r\n  type\r\n    TStreamHelper = class helper for TStream\r\n      :\r\n    end;\r\n\r\n    TSpecialisedStream = class(TMemoryStream)\r\n      :\r\n    end;\r\n<\/pre>\n<p>In this situation someone may wish to use <strong>TSpecialisedStream<\/strong> but they cannot do so without also bringing that helper class into scope, with the potential that has to break their code using their own <strong>TStream<\/strong> helper (after all, if class helpers are good enough for the creator of TSpecialisedStream, why not everybody else?).<\/p>\n<p>So yes, there are ways to responsibly create and consume class helpers, but <em><span style=\"text-decoration: underline;\">everyone<\/span><\/em> has to stick to a safe pattern if they are to avoid creating &#8220;unsociable&#8221; code.<\/p>\n<p>Unlike <strong>with<\/strong>, <strong>goto<\/strong> or untyped pointers or any other abusable language feature quoted to justify use of this abusable feature, the unique problem with class helpers remains:&nbsp; that abuse risks breaking code other than your own.&nbsp; Yes, you can write bad and even flat-out incorrect code using <strong>with<\/strong> or <strong>goto<\/strong> etc, but you can&#8217;t write code using these things that will fundamentally break code in an entirely separate unit, as you can with a class helper.<\/p>\n<p>It also remains the case that (so far at least) with the exception of the original, highly specialised purpose for which class helpers were created (VCL \/ VCL.NET compatability at the framework level) there is no use to which a class helper can be put for which a safer alternative does not exist, and in many cases those alternatives are arguably &#8220;better&#8221; for reasons other than just being considerate.<\/p>\n<h3>The Verdict<\/h3>\n<p>I believe (and this is after all a <span style=\"text-decoration: underline;\">personal<\/span> blog, reflecting the thoughts and opinions of it&#8217;s author which I in no way seek to <span style=\"text-decoration: underline;\">impose<\/span> on others) the warning issued with class helpers is justified and a non-class helper approach should always be preferred where such an approach exists.<\/p>\n<p>But if someone is going to insist on using class helpers in code that may be &#8211; and most especially if it is intended to be &#8211; shared with others, then they should do the community the courtesy of implementing those helpers in the above described fashion, so as to avoid the risk of breaking other people&#8217;s code.<\/p>\n<p>It would seem to me to be the responsible and considerate approach.<\/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\">4<\/span> <span class=\"rt-label rt-postfix\">minutes]<\/span><\/span> My previous post on class helpers provoked a passionate response from some quarters who believed that they could be used &#8220;safely&#8221;.&nbsp; More worrying was an apparent belief that their use was actually endorsed by CodeGear &#8211; tacitly or otherwise.&nbsp; A rather odd view given the advice from CodeGear themselves is to not use them. No-one [&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],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p1TKYv-4y","jetpack_sharing_enabled":true,"jetpack-related-posts":[{"id":273,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/273\/","url_meta":{"origin":282,"position":0},"title":"Class Helpers On Trial","date":"30 Aug 2008","format":false,"excerpt":"Class helpers (introduced in Delphi 2007 2006 2005 - 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\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":282,"position":1},"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":282,"position":2},"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":282,"position":3},"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":[]},{"id":1938,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/1938\/","url_meta":{"origin":282,"position":4},"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":282,"position":5},"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":[]}],"_links":{"self":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/282"}],"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=282"}],"version-history":[{"count":2,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/282\/revisions"}],"predecessor-version":[{"id":1940,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/282\/revisions\/1940"}],"wp:attachment":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/media?parent=282"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/categories?post=282"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/tags?post=282"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}