{"id":1356,"date":"2013-02-15T09:18:45","date_gmt":"2013-02-14T21:18:45","guid":{"rendered":"https:\/\/www.deltics.co.nz\/blog\/?p=1356"},"modified":"2013-02-15T09:27:46","modified_gmt":"2013-02-14T21:27:46","slug":"hint-using-a-wrong-to-make-a-wrong-wrong-right","status":"publish","type":"post","link":"https:\/\/www.deltics.co.nz\/blog\/posts\/1356\/","title":{"rendered":"Hint: Using a Wrong to Make a Wrong Wrong Right"},"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>Yesterday I found myself having to write some code that would never be used in order to co-erce the compiler into not complaining that something would not be used when in fact it was.<br \/>\n<!--more--><\/p>\n<p>Something I have learned over the years is that hints and warnings are useful guides to code quality.  That being the case, I make a point of ensuring that in (final) code, all hints and warnings are addressed, so that if any new hints or warnings appear, they are a useful &#8220;Red Flag&#8221; that warrants investigation.<\/p>\n<p>As soon as you accept that &#8220;1 or 2 hints\/warnings&#8221; may be tolerated, you might as well give up on them as any sort of useful indicator at all, because those &#8220;1 or 2&#8221; will quickly become &#8220;5 or 10&#8221; then &#8220;10 or 20&#8221; etc etc.<\/p>\n<p>Hints and warning often crop up during, for example, refactoring sessions, as variables get removed, procedures become redundant etc etc.  Hints about unused variables and unused procedures then become even more useful because they tell me what I can now remove from my refactored code.<\/p>\n<p>Except yesterday, when the compiler &#8220;HINT&#8221;ed me that I now had a procedure that wasn&#8217;t being used when I knew for a fact, and could demonstrate, that it was!<\/p>\n<p>The situation was a little odd, I grant you.  I had two overloaded forms of a private method, one of which was in turn called via a public method (but which I didn&#8217;t wish to expose publicly directly itself) and the other which was in turn called by another private method, but indirectly.<\/p>\n<p>To borrow a feature from Raymond Chen&#8217;s blog:<\/p>\n<p><em><strong>Pre-emptive Nitpickers Corner:<\/strong>  I am not interested in how what I am about to show might be done differently.  There are aspects of the class that are not directly relevant to the issue at hand which influence how the code ended up this way.  The implementation details are not the issue; the behaviour from the compiler is what is under examination here.<\/em><\/p>\n<p>WIth that out of the way, here are the salient aspects of the class:<\/p>\n<pre class=\"brush: delphi; title: ; notranslate\" title=\"\">\r\nTFoo = class\r\n  private\r\n    procedure Call(aProc: TNotifyEvent);\r\n    procedure InternalDelete; overload;\r\n    procedure InternalDelete(Sender: TObject); overload;\r\n  public\r\n    procedure Delete;\r\n  end;\r\n<\/pre>\n<p>The <strong>public<\/strong> <em>Delete<\/em> method calls <em>InternalDelete()<\/em>, so <em>InternalDelete()<\/em> is used.<\/p>\n<p>The <strong>private<\/strong> <em>InternalDelete()<\/em> method ends up calling <em>Call(InternalDelete)<\/em> and there are very good reasons why it doesn&#8217;t simply call it directly itself.  You can see from the declaration of the <em>Call()<\/em> method that the &#8220;<em>InternalDelete<\/em>&#8221; referenced here is the <em>InternalDelete(Sender)<\/em> method.  So <em>InternalDelete(Sender)<\/em> is also used.<\/p>\n<p>However, the compiler insists on hinting that <em>InternalDelete(Sender)<\/em> is <strong>not<\/strong> used.  The fact that it is &#8220;referenced&#8221; isn&#8217;t enough for the compiler to consider it &#8220;used&#8221;.<\/p>\n<p>How to deal with this ?<\/p>\n<p>Well, there are (at least) two ways to skin this particular cat, but let&#8217;s look at the most interesting and fun way first.  With a compiler this easily fooled I thought I would see if I could use that foolishness to solve the &#8220;problem&#8221;.<\/p>\n<p>What I needed was someway of making the compiler see that I was calling this method.  A simple solution is to add an <strong>initialization<\/strong> section to the unit containing the class, instantiate the class and call the method (exploiting the fact that &#8220;private&#8221; class members are only <strong>private<\/strong> outside the unit in which they are declared):<\/p>\n<pre class=\"brush: delphi; title: ; notranslate\" title=\"\">\r\ninitialization\r\n  with TFoo.Create do\r\n  begin\r\n    InternalDelete(NIL);\r\n    Free;\r\n  end;\r\n<\/pre>\n<p><em><strong>Another Pre-emptive Nitpickers Corner:<\/strong> This is one of those cases where &#8220;with&#8221; is entirely safe and entirely harmless.  If you can&#8217;t deal with the fact that such cases exist and have a dogmatic-bordering-on-religious objection to the use of <strong>with<\/strong> please keep it to yourself.  It is not the subject under discussion.  \ud83d\ude42<\/em><\/p>\n<p>Anyhoo, sure enough, this is enough to satisfy the compiler that the method is in fact used and so it now keeps quiet about hinting that it is not.  But the <em>InternalDelete(Sender)<\/em> method is not designed to be called with a <strong>NIL<\/strong> object reference so this code actually causes a crash in the real code.  We could deal with that by introducing some redundant safety checks within the <em>InternalDelete()<\/em> method (redundant because those safety checks are applied where necessary by the methods that <strong>call<\/strong> the internal method in the first place).  But so far we haven&#8217;t really taken advantage of any foolishness in the compiler, so it seems a bit premature to go adding more foolishness of our own.<\/p>\n<p>We only need the compiler to <em>think<\/em> the method is called, but we don&#8217;t want the code that does the calling to ever be executed.  The simplest way of leaving code in place that does nothing is to put it inside a conditional flow where the condition is never met (a comment isn&#8217;t &#8220;code&#8221;, so &#8220;commenting out&#8221; does not fit the criteria).<\/p>\n<p>So let&#8217;s try that:<\/p>\n<pre class=\"brush: delphi; title: ; notranslate\" title=\"\">\r\ninitialization\r\n  if FALSE then with TFoo.Create do\r\n  begin\r\n    InternalDelete(NIL);\r\n    Free;\r\n  end;\r\n<\/pre>\n<p>Surely the compiler is smart enough to figure out that this code is a no-op and won&#8217;t even bother compiling it, and thus our erroneous hint re-surfaces ?<\/p>\n<p>Actually, no.  This <em>is<\/em> enough to fool the compiler and thus, assured that this code will never actually be called we can get really dirty and dispense with the &#8220;with&#8221; (do I hear cheers at the back there ? \ud83d\ude42 ):<\/p>\n<pre class=\"brush: delphi; title: ; notranslate\" title=\"\">\r\ninitialization\r\n  if FALSE then TFoo.Create.InternalDelete(NIL);\r\n<\/pre>\n<p>As much fun as it might be to blind-side the compiler like this, you might rail at such skulduggery, which brings us to the second way of dealing with the situation:  Disabling hints on the specific procedure in question.<\/p>\n<pre class=\"brush: delphi; title: ; notranslate\" title=\"\">\r\nTFoo = class\r\n  private\r\n    procedure Call(aProc: TNotifyEvent);\r\n    procedure InternalDelete; overload;\r\n  {$hints OFF}\r\n    procedure InternalDelete(Sender: TObject); overload;\r\n  {$hints ON}\r\n  public\r\n    procedure Delete;\r\n  end;\r\n<\/pre>\n<p>The trouble is, this means that if ever the code is refactored and the <em>InternalDelete(Sender) <\/em>method truly does become unused, you will never find out about it.  This is also the case with the sneaky no-op initialization code method, but the mechanism required to deal with this potential future problem is going to be messy, involving a custom define to stop this or any similar hint suppression:<\/p>\n<pre class=\"brush: delphi; title: ; notranslate\" title=\"\">\r\nTFoo = class\r\n  private\r\n    procedure Call(aProc: TNotifyEvent);\r\n    procedure InternalDelete; overload;\r\n  {$ifNdef ALLHINTS} {$hints OFF} {$endif}\r\n    procedure InternalDelete(Sender: TObject); overload;\r\n  {$hints ON}\r\n  public\r\n    procedure Delete;\r\n  end;\r\n<\/pre>\n<p>There is a whole separate discussion to be had about hint suppression and how to ensure that if the compiler behaviours in this area ever change, how those changes might affect any technique used to suppress the erroneous hint in the meantime.<\/p>\n<p>But I shall deal with those if and when they arise, but with the way Delphi development has been going lately, I shan&#8217;t hold my breath waiting for the compiler to be fixed in this area.<\/p>\n<p>The only thing left for me to check is whether hints can be suppressed on individual procedures within a class declaration in Delphi 7 (my minimum to-be-supported version).  I have a vague recollection that at some point warnings could only be turned off for an entire class in older versions.  Whether that changed pre or post Delphi 7 and whether it applied to hints as well as warnings, I have yet to verify.<\/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> Yesterday I found myself having to write some code that would never be used in order to co-erce the compiler into not complaining that something would not be used when in fact it was.<\/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":true,"jetpack_social_options":[]},"categories":[4],"tags":[71,292,197,198],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p1TKYv-lS","jetpack_sharing_enabled":true,"jetpack-related-posts":[{"id":2223,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/2223\/","url_meta":{"origin":1356,"position":0},"title":"When You Say Nothing At All&#8230;","date":"10 Mar 2014","format":false,"excerpt":"This is another one of those posts that has a bit of a double meaning in the same title. First, there is the matter of a useful hint\/warning that I think could be emitted by a Pascal compiler. The other is what I have been up to in recent months\u2026","rel":"","context":"In &quot;Delphi&quot;","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":563,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/563\/","url_meta":{"origin":1356,"position":1},"title":"Delphi Unicode = Wide-ANSI","date":"26 Sep 2009","format":false,"excerpt":"Be careful what you wish for. A lot of people were overjoyed to hear that Unicode support was coming to Delphi. Some were skeptical of the chosen implementation approach however, it all seemed just a little bit too easy. I was one, and sadly it seems I was right. I've\u2026","rel":"","context":"In &quot;Delphi&quot;","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":426,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/426\/","url_meta":{"origin":1356,"position":2},"title":"The &#8220;Big Switch&#8221;","date":"28 Apr 2009","format":false,"excerpt":"Much has been made in the past and again more recently, about the lack of a compiler switch in Delph 2009 to govern the behaviour of the String type. CodeGear have repeatedly said that it was not possible\/practical to provide such a switch, but their advice to anyone concerned about\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":1356,"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":2337,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/2337\/","url_meta":{"origin":1356,"position":4},"title":"A Silent Danger&#8230;","date":"07 Jun 2015","format":false,"excerpt":"A brief post on a long standing omission in type checking in Pascal and the limitations of Range Checking as applied to the problem. Consider this contrived example of a simple function: This very simple function accepts an explicitly 32-bit Integer parameter and simply returns TRUE if the value passed\u2026","rel":"","context":"In &quot;Delphi&quot;","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":2344,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/2344\/","url_meta":{"origin":1356,"position":5},"title":"A Deeper Dive into Range Checking","date":"08 Jun 2015","format":false,"excerpt":"Yesterday I posted about an issue with type checking in Delphi (and other Pascal) compilers. As mentioned in that post, range checking is fundamentally flawed as a supposed solution to the problem for reasons that are explored further in this post. To recap: Range checking does not test the types\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\/1356"}],"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=1356"}],"version-history":[{"count":7,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/1356\/revisions"}],"predecessor-version":[{"id":1362,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/1356\/revisions\/1362"}],"wp:attachment":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/media?parent=1356"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/categories?post=1356"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/tags?post=1356"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}