{"id":683,"date":"2010-11-21T08:35:11","date_gmt":"2010-11-20T20:35:11","guid":{"rendered":"https:\/\/www.deltics.co.nz\/blog\/?p=683"},"modified":"2010-11-21T09:59:01","modified_gmt":"2010-11-20T21:59:01","slug":"class-helpers-extending-classes-for-context","status":"publish","type":"post","link":"https:\/\/www.deltics.co.nz\/blog\/posts\/683\/","title":{"rendered":"Class Helpers: Extending Classes for Context"},"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>NEWSFLASH: I believe I have found a use for class helpers in the wild!<\/p>\n<p>This, even though <a href=\"https:\/\/www.deltics.co.nz\/blog\/?p=273\">I have long held the view that class helpers should not be viewed as a general purpose utility<\/a>.  They were designed for a very specific purpose and the authors of the technology themselves tell us how they are intended to be used.  Using them in other ways is asking for trouble:  they can break your &#8211; or others &#8211; code, they hide details of an implementation in <strong>A Bad Way<\/strong>\u2122 and you are likely to <a href=\"http:\/\/tech.turbu-rpg.com\/250\/tthreadedqueue-interesting-but-incomplete\">run into limitations because what you want to use them for doesn&#8217;t tally with what they are intended to be used for<\/a>.<\/p>\n<p>But, somewhat to my surprise, I have recently found what I consider to be a legitimate use for them.  Less surprisingly, it actually fits with their intended use.<\/p>\n<p><!--more--><\/p>\n<h2>First, The Context<\/h2>\n<p>I am currently implementing a client\/server system.  Not an SQL client\/server, but a REST client server.  That is, a Delphi application server which exposes services to a Delphi GUI client using REST to invoke those services and JSON to transport object representations between client and server.<\/p>\n<p>I have classes that are used in both client and server contexts.  For example, I have a class representing a property list &#8211; a list of named and typed values.<\/p>\n<p>A client receives a property list in response to some request to the server in the form of a JSON array, and also it sends propertly lists to the server as part of a request.  Obviously the ability for a property list to serialise to\/from JSON is necessary in both client and server contexts for this class, and so it is an intrinsic behaviour to that class.<\/p>\n<p>However, the client has other things that it is useful to do with an instance of that class.<\/p>\n<p>For example, when updating a form in the GUI, it will wish to apply string values from a property list to edit controls, booleans to check-boxes\/radio buttons, enum value to combo-boxes.. etc etc.<\/p>\n<p>Clearly, putting methods to assist with these behaviour on the class is inappropriate since in the server context such methods have no use what-so-ever and would only pollute the interface on the class.<\/p>\n<p>But having a client-side specific sub-class is also over-kill.  I do not want to have remember that when coding in the GUI I use the <strong>TClientPropertyList<\/strong> rather than <strong>TPropertyList<\/strong>.  Equally I do not really want to have to invoke cumbersome first-class procedures such as <strong>SetCheckboxFromProperty( propList, checkbox )<\/strong> when the more intuitive <strong>propList.SetCheckbox( checkbox )<\/strong> could be made available.<\/p>\n<p>Class helpers actually have a role here, and it fits the original vision perfectly.<\/p>\n<h2>A Class To Help &#8211; A Class Helper<\/h2>\n<p>Let us briefly revisit the vision for class helpers, in the form of the documentation:<\/p>\n<blockquote><p>You can use the class helper any place where you can legally use the extended class. The compiler&#8217;s resolution scope then becomes the original class, plus the class helper. <\/p>\n<p>Class helpers provide a way to extend a class, but they should not be viewed as a design tool to be used when developing new code. They should be used solely for their intended purpose, which is language and platform RTL binding.\n<\/p><\/blockquote>\n<p>One thing to be wary of is the directive w.r.t using them as a design tool for new code, but in my case I believe that the fact that I am employing the helper to assist with &#8220;platform RTL binding&#8221; overrides this concern.  I am creating a platform &#8211; my application architecture &#8211; and what I am doing by employing a class helper in this case, is extending a class in a particular, and unambiguous, context within that platform.<\/p>\n<p>That is, I am creating an extension for a class which is relevant only to client code on my platform.<\/p>\n<p>Furthermore, I &#8220;own&#8221; both the original class and the context in which it is being used.  There is no risk here that my helper will break or otherwise interfere with another helper for the same class.  If I ever need to embellish the original class, I will simply do so, and ensure that the client-context helper provided by the platform is updated accordingly, if necessary.<\/p>\n<h2>The Resulting Architecture<\/h2>\n<p>What I ended up with was 2 units:<\/p>\n<pre class=\"brush: delphi; title: ; notranslate\" title=\"\">\r\n   Project.PropertyList;   \/\/ Contains the TPropertyList itself\r\n   Project.Client.Utils;     \/\/ Contains the client-side TPropertyListHelper among other things\r\n<\/pre>\n<p>The server project obviously doesn&#8217;t employ any of the <strong>Project.Client.*<\/strong> units.  The client projects employ both the property list but then also use the client specific Utils unit if\/when required.<\/p>\n<p>When I am coding up the GUI for my project in the client, I add <strong>Project.Client.Utils<\/strong> to my uses list and my <strong>TPropertyList<\/strong> instances are now endowed with GUI\/client specific methods to help get\/set values from GUI controls.  If my client code is not actually concerned with GUI aspects, then it simply works with <strong>TPropertyList<\/strong> as-is, without even bringing the helper into scope if not required.<\/p>\n<p>When I am coding up the server-side code, I simply work with <strong>TPropertyList<\/strong> itself.<\/p>\n<p>And if I ever need any server-side specific extensions to the class (for example, adding methods to persist a propertly list in an SQL database on the server-side), I could introduce a server-side helper into <strong>Project.Server.Utils<\/strong>.<\/p>\n<p>So there is a valid use for class helpers, but I still maintain that using a class helper to extend\/embellish classes from *other* libraries\/frameworks is <strong>A Bad Idea<\/strong>\u2122, because you potentially won&#8217;t be the only person with an idea of what makes a good extension\/embellishment to that class.  As soon as you share code with someone who has different ideas, one or other of you is going to have to <em>change<\/em> their ideas and, potentially, a great deal of code.<\/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> 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 tell us how they are [&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-b1","jetpack_sharing_enabled":true,"jetpack-related-posts":[{"id":282,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/282\/","url_meta":{"origin":683,"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":1207,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/1207\/","url_meta":{"origin":683,"position":1},"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":825,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/825\/","url_meta":{"origin":683,"position":2},"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":273,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/273\/","url_meta":{"origin":683,"position":3},"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":1938,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/1938\/","url_meta":{"origin":683,"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":683,"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\/683"}],"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=683"}],"version-history":[{"count":10,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/683\/revisions"}],"predecessor-version":[{"id":692,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/683\/revisions\/692"}],"wp:attachment":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/media?parent=683"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/categories?post=683"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/tags?post=683"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}