{"id":507,"date":"2009-09-14T23:21:02","date_gmt":"2009-09-14T11:21:02","guid":{"rendered":"https:\/\/www.deltics.co.nz\/blog\/?p=507"},"modified":"2009-09-14T23:30:40","modified_gmt":"2009-09-14T11:30:40","slug":"mind-the-gaps","status":"publish","type":"post","link":"https:\/\/www.deltics.co.nz\/blog\/posts\/507\/","title":{"rendered":"Mind the Gap(s)"},"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>This is what I love about Delphi. \u00a0After almost 15 years of Delphi&#8217;ing there&#8217;s still new things to learn, and I don&#8217;t just mean new features in the latest releases. \u00a0I mean, basic, fundamental things that have been there for years, just undiscovered (by me). \u00a0In this case the discovery was a little annoying, but never-the-less\u00a0educational.<\/p>\n<p><!--more--><\/p>\n<p>In the case in question I was creating some library code for myself to help with some resource manipulation code that I have in mind. \u00a0As part of this I wanted an enum type to represent the normal resource types found in Windows code:<\/p>\n<pre class=\"brush: delphi; title: ; notranslate\" title=\"\">\r\n  type\r\n    TResourceType = (\r\n                      rtCURSOR = 1,\r\n                      rtBITMAP,\r\n                      rtICON,\r\n                      rtMENU,\r\n                      rtDIALOG,\r\n                      rtSTRING,\r\n                      rtFONTDIR,\r\n                      rtFONT,\r\n                      rtACCELERATOR,\r\n                      rtRCDATA,\r\n                      rtMESSAGETABLE,\r\n                      rtGROUP_CURSOR,\r\n                      rtGROUP_ICON = 14,\r\n                      rtVERSION = 16,\r\n                      rtDLGINCLUDE,\r\n                      rtPLUGPLAY = 19,\r\n                      rtVXD,\r\n                      rtANICURSOR,\r\n                      rtANIICON,\r\n                      rtHTML,\r\n                      rtMANIFEST\r\n                    );\r\n    TResourceTypes = set of TResourceType;\r\n<\/pre>\n<p>I used specific ordinal assignments to some of the enum members to create the necessary &#8220;gaps&#8221; for the resource type values that aren&#8217;t (currently) meaningful in Windows and ensure that the ordinal values of the enum members corresponded exactly to Windows resource type values.<\/p>\n<p>The enum member names are also carefully chosen so that they may be quickly converted to the symbolic names of the corresponding Windows resource type identifiers, e.g.:<\/p>\n<p style=\"padding-left: 30px;\">rtCURSOR        &gt;&gt;  RT_CURSOR<br \/>\nrtGROUP_ICON  &gt;&gt; RT_GROUP_ICON<br \/>\netc<\/p>\n<p>The plan was to have a function to take a <strong>TResourceType<\/strong> value, convert to the enum name and change the &#8220;rt&#8221; prefix to &#8220;RT_&#8221;.  This is not exactly rocket science and I did not anticipate any problems.<\/p>\n<p>So I was somewhat surprised to find myself thwarted by a compilation error in the code:<\/p>\n<pre class=\"brush: delphi; title: ; notranslate\" title=\"\">\r\n      sName := GetEnumName(TypeInfo(TResourceType), Ord(aValue));\r\n<\/pre>\n<p><span style=\"color: #ff0000;\"><strong>ERROR: <span style=\"color: #000000;\">E2134 &#8211; Type &#8216;TResourceType&#8217; has no typeinfo&#8217;<\/span><\/strong><\/span><\/p>\n<p>It took me a while to chase this down &#8211; my initial thought was to suspect that there was some other definition of a <strong>TResourceType<\/strong> type that was hiding my type.  That was soon ruled out and a big of further digging eventually revealed the answer.<\/p>\n<p>It turns out that assigning specific ordinal values to enum members (if they are different to the ordinals that the compiler would normally assign automatically) defeats the RTTI system and prevents the creation of type info for the type. \u00a0Sadly this doesn&#8217;t seem to be mentioned in the documentation, not even for the <strong>E2134<\/strong> error itself which would seem to be an ideal help topic to contain this useful piece of information.<\/p>\n<p>The solution in my case was quite simple. \u00a0The number of &#8220;unused&#8221; members was small so I could change my enum type to:<\/p>\n<pre class=\"brush: delphi; title: ; notranslate\" title=\"\">\r\n  type\r\n    TResourceType = (\r\n                      rtNotUsed1,    \/\/ = 0\r\n                      rtCURSOR,\r\n                      rtBITMAP,\r\n                      rtICON,\r\n                      rtMENU,\r\n                      rtDIALOG,\r\n                      rtSTRING,\r\n                      rtFONTDIR,\r\n                      rtFONT,\r\n                      rtACCELERATOR,\r\n                      rtRCDATA,\r\n                      rtMESSAGETABLE,\r\n                      rtGROUP_CURSOR,\r\n                      rtNotUsed2,    \/\/ = 13\r\n                      rtGROUP_ICON,\r\n                      rtNotUsed3,    \/\/ = 15\r\n                      rtVERSION,\r\n                      rtDLGINCLUDE,\r\n                      rtNotUsed4,    \/\/ = 18\r\n                      rtPLUGPLAY,\r\n                      rtVXD,\r\n                      rtANICURSOR,\r\n                      rtANIICON,\r\n                      rtHTML,\r\n                      rtMANIFEST\r\n                    );\r\n    TResourceTypes = set of TResourceType;\r\n<\/pre>\n<p>Notice the additional <strong>rtNotUsedN<\/strong> members which fill in the gaps.<\/p>\n<p>This created a slight problem for me in that now I had some undesirable names &#8220;polluting&#8221; my enum space.  In this case I was not too concerned about that &#8211; they are self documenting after all (&#8220;NotUsed&#8221; is pretty unambiguous on that score).<\/p>\n<p>But there were occasions in my code where I was going to wish to test some <strong>TResourceType<\/strong> value to ensure that it was valid.<\/p>\n<p>A simple pair of sets helped out with this:<\/p>\n<pre class=\"brush: delphi; title: ; notranslate\" title=\"\">\r\n  const\r\n    rtInvalid = [rtNotUsed1, rtNotUsed2, rtNotUsed3, rtNotUsed4];\r\n    rtValidResourceTypes  = [Low(TResourceType)..High(TResourceType)] - rtInvalid;\r\n<\/pre>\n<p>Which allowed me to perform runtime checking of some arbitrary <strong>TResourceType<\/strong> value:<\/p>\n<pre class=\"brush: delphi; title: ; notranslate\" title=\"\">\r\n    if NOT (aValue in rtValidResourceTypes) then\r\n      \/\/ Invalid resource type ... !\r\n<\/pre>\n<p>Or of course alternatively:<\/p>\n<pre class=\"brush: delphi; title: ; notranslate\" title=\"\">\r\n    if (aValue in rtInvalid) then\r\n      \/\/ Invalid resource type ... !\r\n<\/pre>\n<p>According to taste (you can probably tell which I prefer as the choice of names for the sets yields one which reads quite fluently and naturally, whilst the other is awkward and stilted in comparison, albeit more brief).  \ud83d\ude42<\/p>\n<h2>We Don&#8217;t Know What We Don&#8217;t Know<\/h2>\n<p>It&#8217;s really quite astonishing to me that in almost 15 years of working with Delphi I&#8217;ve not previously encountered this limitation of the type information system (as it relates to enum types).  So astonishing that I thought it worth not just blogging about but also posting to <a href=\"http:\/\/stackoverflow.com\/questions\/1420562\/why-do-i-get-type-has-no-typeinfo-error-with-an-enum-type\">stackoverflow<\/a> as a question with a ready made answer.<\/p>\n<p>I&#8217;ve only recently started using stackoverflow seriously &#8211; I hope this sort of self-answering isn&#8217;t an abuse of the system.  I thought it a useful way of adding to the &#8220;knowledgebase&#8221;.<\/p>\n<p>In any event, Barry Kelly, a CodeGear compiler engineer who works on the Delphi compiler itself no less (some guys get all the luck!) responded to my stackoverflow question+answer by explaining some of the internal details of the RTTI system that makes typeinfo  difficult\/impossible for such non-contiguous enum types, and offered the opinion that it probably wasn&#8217;t worth going to too much bother for since the times when it would be useful were so rare.<\/p>\n<p>I&#8217;d have to agree with him.<\/p>\n<p>It&#8217;s taken me 15 years to stumble across it &#8211; I think I can manage without a &#8220;fix&#8221; in this case.<\/p>\n<h2>Footnote<\/h2>\n<p>If this had been a somewhat simpler case where I simply wanted the initial member of the enum to have a value such as 1 (one) rather than the usual 0 (zero), I could have achieved type safety with a simple subrange type (thanks to Ulrich for pointing this out on stackoverflow) renaming the underlying type and using the subrange type as the &#8220;concrete&#8221; representation of my enum throughout my code (having established the principle, in this final example I have artifically reduced the number of members in the enum type, simply to keep it short and concise):<\/p>\n<pre class=\"brush: delphi; title: ; notranslate\" title=\"\">\r\n  type\r\n    TResourceTypeValue = (\r\n                            rtUnused,\r\n                            rtCURSOR,\r\n                            rtBITMAP,\r\n                            rtICON,\r\n                            rtMENU\r\n                 );\r\n    TResourceType = rtCURSOR..High(TResourceTypeValue);\r\n    TResourceTypes = set of TResourceType;\r\n<\/pre>\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> This is what I love about Delphi. \u00a0After almost 15 years of Delphi&#8217;ing there&#8217;s still new things to learn, and I don&#8217;t just mean new features in the latest releases. \u00a0I mean, basic, fundamental things that have been there for years, just undiscovered (by me). \u00a0In this case the discovery was a little annoying, but [&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":[292,88,87,86],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p1TKYv-8b","jetpack_sharing_enabled":true,"jetpack-related-posts":[{"id":586,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/586\/","url_meta":{"origin":507,"position":0},"title":"Absolute (for) Beginners","date":"15 Oct 2009","format":false,"excerpt":"I casually suggested the use of the \"absolute\" keyword in response to a question on the NZ DUG mailing list today. \u00a0I thought nothing of it but someone mentioned that it had been years since he'd seen anyone use it, so I thought maybe it was worth bringing to wider\u2026","rel":"","context":"In &quot;Delphi&quot;","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":760,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/760\/","url_meta":{"origin":507,"position":1},"title":"Platform Independence Version Dependencies in the XE2 RTL","date":"14 Sep 2011","format":false,"excerpt":"So I have spent about a week now with XE2 and FireMonkey and thought I would share some of the experience so far. After an initial peek and poke around, the first order of business for me was to migrate some of my existing code to the new RTL. First\u2026","rel":"","context":"In &quot;Delphi&quot;","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":1397,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/1397\/","url_meta":{"origin":507,"position":2},"title":"Qualified Enum Reference That Fails to Compile in XE4 (and rightly so)","date":"01 May 2013","format":false,"excerpt":"Running through some of my code last night, putting them through the new XE4 compiler, threw up a real oddity: Some code that used to compile just fine, which no longer compiles in XE4 and which should not have compiled before! It's an odd one, because the code previously compiled\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":507,"position":3},"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":338,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/338\/","url_meta":{"origin":507,"position":4},"title":"Delphi 2009 &#8211; A Heads-Up for Low-Level Coders","date":"13 Sep 2008","format":false,"excerpt":"Prompted by a conversation with some colleagues where-in we collectively speculated about the implementation details of a generic class and what impact - if any - this might have on performance vs a \"traditional\" polymorphic equivalent, I threw together a quick performance test case in my Smoketest framework, and as\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":507,"position":5},"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":[]}],"_links":{"self":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/507"}],"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=507"}],"version-history":[{"count":21,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/507\/revisions"}],"predecessor-version":[{"id":527,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/507\/revisions\/527"}],"wp:attachment":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/media?parent=507"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/categories?post=507"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/tags?post=507"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}