{"id":208,"date":"2008-08-19T22:34:44","date_gmt":"2008-08-19T10:34:44","guid":{"rendered":"https:\/\/www.deltics.co.nz\/blog\/?p=208"},"modified":"2008-08-20T10:51:27","modified_gmt":"2008-08-19T22:51:27","slug":"when-typenames-collide","status":"publish","type":"post","link":"https:\/\/www.deltics.co.nz\/blog\/posts\/208\/","title":{"rendered":"When Type(name)s Collide"},"content":{"rendered":"<span class=\"span-reading-time 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>It&#8217;s funny how this happens.\u00a0 I was already intending to write about the way I have exploited like-type names to my advantage, and then noticed that the same subject cropped up recently in the <a href=\"https:\/\/forums.codegear.com\/category.jspa?categoryID=12\" target=\"_blank\">re-invented Delphi forums<\/a>.\u00a0 In that instance, the issue though was a <span style=\"text-decoration: underline;\">problem<\/span>, and one that I&#8217;m sure many will be familiar with:\u00a0 <a href=\"https:\/\/forums.codegear.com\/message.jspa?messageID=3331&amp;tstart=0\" target=\"_blank\">When is a TBitmap not a TBitmap<\/a>?<\/p>\n<p>In my case, the question is: <em>When is a TForm not TForm<\/em>?<\/p>\n<p><!--more--><\/p>\n<h3>Keeping The VCL At Arms Length<\/h3>\n<p>A very large number of moons ago I was briefly involved in a <a href=\"http:\/\/en.wikipedia.org\/wiki\/PowerBuilder\" target=\"_blank\">PowerBuilder<\/a> project (anybody else remember when 4GL&#8217;s were going to save the software development industry from itself?).<\/p>\n<p>When OO reached PowerBuilder it brought with it an extensible component model &#8211; the PowerBuilder equivalent of the VCL &#8211; the PFC (<em>PowerBuilder Foundation Class<\/em> library).\u00a0 The team I was working with had learned from experience to keep the PFC at arms length.<\/p>\n<p>Objects in the application were <em><span style=\"text-decoration: underline;\">never<\/span><\/em> instances of PFC classes, but of derived classes, even if the class derived added or changed nothing in the base class.<\/p>\n<p>The reason being of course that if ever a problem was later discovered in the PFC class, or if some new behaviour or feature were desirable in the foundation classes, the additional class between the application and the PFC gave the developers an opportunity to make changes that would instantly propogate into all corners of their project, without having to modify the PFC itself, protecting themselves to an extent from changes in future versions of the PFC.<\/p>\n<p>In Delphi terms this would mean for example never using a <strong>TButton<\/strong>, but instead declaring a <strong>TMyButton<\/strong> class and always using that as the &#8220;fundamental base class&#8221; for <span style=\"text-decoration: underline;\">all<\/span> buttons (and button classes) in your projects.<\/p>\n<p>Adopting a comprehensive layer of intermediate classes to sit between an application and the VCL is obviously a huge, and largely pointless, task &#8211; the VCL is a very different beast than the PFC ever was.<\/p>\n<p>But in the case of <strong>TForm<\/strong> an intermediate class could be useful, adding capabilities to forms that are widely, if not universally, useful.<\/p>\n<p>The <strong>TBitmap<\/strong> problem identifies the mechanism to make an intermediate class instantly useful.\u00a0 The two <strong>TBitmap<\/strong> types caused problems because they were actually very different types and utterly incompatible.\u00a0 But having the same name wasn&#8217;t, itself, a problem.\u00a0 Just unfortunate.<\/p>\n<p>With a little care, we can make like-names work <em>for<\/em> us.<\/p>\n<h3>A New TForm<\/h3>\n<p>To avoid the problems that occur with <strong>TBitmap<\/strong> we need to be careful to make any new <strong>TForm<\/strong> compatible with the VCL original.\u00a0 But isn&#8217;t that exactly what OO gives us?\u00a0 (One of the things anyway).<\/p>\n<p>Consider this declaration:<\/p>\n<pre class=\"delphi\">  unit Deltics.Forms;\r\n\r\ninterface\r\n\r\n  uses\r\n    Forms;\r\n\r\n  type\r\n    TForm = class(Forms.TForm)\r\n    end;\r\n\r\nimplementation\r\n\r\nend.<\/pre>\n<p>This new <strong>TForm<\/strong> is compatible with <strong>TForm<\/strong> &#8211; it is a direct descendant.  Anywhere that a <strong><em>Forms<\/em>.TForm<\/strong> can be referenced, a <strong><em>Deltics.Forms<\/em>.TForm<\/strong> is also sure to be perfectly valid because, unlike in the case of that <strong>TBitmap<\/strong> example, it <em><span style=\"text-decoration: underline;\">is<\/span><\/em> in fact a <strong>Forms.TForm<\/strong>.<\/p>\n<p>It also happens to have exactly the same name, so any existing &#8211; or, more importantly, automatically generated &#8211; code that doesn&#8217;t know about my new form class can be made to use it simply by ensuring that the unit containing it is in scope.<\/p>\n<p>Note that I am <span style=\"text-decoration: underline;\">not<\/span> talking about visual form inheritance here.<\/p>\n<h3>Now We Have It, What To Do With It?<\/h3>\n<p>Before going too far, let us first see how we incorporate this new <strong>TForm<\/strong> into our applications by looking at the boiler-plate code generated by the IDE when we create a new form in our projects:<\/p>\n<pre class=\"delphi\">  unit Unit1;\r\n\r\ninterface\r\n\r\nuses\r\n  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,\r\n  Dialogs;\r\n\r\ntype\r\n  TForm1 = class(TForm)\r\n    procedure FormCreate(Sender: TObject);\r\n  private\r\n    { Private declarations }\r\n  public\r\n    { Public declarations }\r\n  end;<\/pre>\n<p>All we need to do is add the <strong>Deltics.Forms<\/strong> unit to the <strong>uses<\/strong> list in such a way that the <strong>TForm<\/strong> in that unit &#8220;hides&#8221; the <strong>TForm<\/strong> in the <strong>Forms<\/strong> unit.\u00a0 This means adding it <em>after<\/em> the <strong>Forms<\/strong> unit:<\/p>\n<pre class=\"delphi\">uses\r\n  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,\r\n  Dialogs,\r\n  Deltics.Forms;<\/pre>\n<p>That&#8217;s it.\u00a0 (We could of course just replace <strong>Forms<\/strong> with <strong>Deltics.Forms<\/strong> but there are other things in the <strong>Forms<\/strong> unit that we will likely want to refer to).<\/p>\n<p>Either way, the <strong>TForm<\/strong> that the <strong>TForm1<\/strong> class derives from is now <strong><em>Deltics.Forms.<\/em>TForm<\/strong>.<\/p>\n<p>Still, this doesn&#8217;t achieve very much other than to play a harmless little prank on the VCL.\u00a0 But what it does is provide us with an opportunity &#8211; we can now introduce things into <strong>TForm<\/strong>, or make changes using normal OO techniques.<\/p>\n<p>For now let&#8217;s just add a fairly trivial new feature &#8211; a property that we can manipulate at runtime to provide our forms with a <a href=\"https:\/\/www.deltics.co.nz\/blog\/?p=193\" target=\"_blank\">size grip<\/a> if we wish (design-time properties are a whole different ball game when it comes to forms).<\/p>\n<p>Again, this is so trivial a download is a bit much, so here&#8217;s the entire unit:<\/p>\n<pre class=\"delphi\">  unit Deltics.Forms;\r\n\r\ninterface\r\n\r\n  uses\r\n    Forms,\r\n    Deltics.Controls.SizeGrip;\r\n\r\n  type\r\n    TForm = class(Forms.TForm)\r\n    private\r\n      fHasSizeGrip: Boolean;\r\n      fSizeGrip: TSizeGrip;\r\n      procedure set_HasSizeGrip(const aValue: Boolean);\r\n      procedure CreateSizeGrip;\r\n    protected\r\n      procedure CreateWnd; override;\r\n      procedure DestroyWnd; override;\r\n    public\r\n      property HasSizeGrip: Boolean read fHasSizeGrip write set_HasSizeGrip;\r\n    end;\r\n\r\nimplementation\r\n\r\n  uses\r\n    SysUtils;\r\n\r\n  procedure TForm.CreateSizeGrip;\r\n  begin\r\n    if NOT HandleAllocated then\r\n      EXIT;\r\n\r\n    fSizeGrip := TSizeGrip.Create(self);\r\n    fSizeGrip.Parent := self;\r\n  end;\r\n\r\n  procedure TForm.CreateWnd;\r\n  begin\r\n    inherited;\r\n    if HasSizeGrip then CreateSizeGrip;\r\n  end;\r\n\r\n  procedure TForm.DestroyWnd;\r\n  begin\r\n    FreeAndNIL(fSizeGrip);\r\n    inherited;\r\n  end;\r\n\r\n  procedure TForm.set_HasSizeGrip(const aValue: Boolean);\r\n  begin\r\n    if (fHasSizeGrip = aValue) then\r\n      EXIT;\r\n\r\n    fHasSizeGrip := aValue;\r\n\r\n    if HasSizeGrip then CreateSizeGrip else FreeAndNIL(fSizeGrip);\r\n  end;\r\n\r\nend.<\/pre>\n<h3>Just The Tip of The TIceBerg<\/h3>\n<p>The <strong>Deltics.Forms<\/strong> unit actually started out with a different purpose and incorporates much more than a few trivial additions to <strong>TForm<\/strong>.<\/p>\n<p>The <strong>Application<\/strong> object gets some attention, and <strong>TForm<\/strong> gets a significant further work-out, a lot of it in the name of <a href=\"http:\/\/www.installationexcellence.com\/articles\/VistaWithDelphi\/Original\/Index.html#Wheres_My_Induction\" target=\"_blank\">Creating Windows Vista Ready applications<\/a>.\u00a0 Since the Vista readiness changes hinge on the <strong>Application<\/strong> object, I shall look at how I achieved that next.<\/p>\n","protected":false},"excerpt":{"rendered":"<p><span class=\"span-reading-time 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>It&#8217;s funny how this happens.\u00a0 I was already intending to write about the way I have exploited like-type names to my advantage, and then noticed that the same subject cropped up recently in the re-invented Delphi forums.\u00a0 In that instance, the issue though was a problem, and one that I&#8217;m sure many will be familiar [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_feature_clip_id":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2},"jetpack_post_was_ever_published":false},"categories":[4],"tags":[292,42,41,40,43],"class_list":["post-208","post","type-post","status-publish","format-standard","hentry","category-delphi","tag-delphi","tag-size-grip","tag-tform","tag-tsizegrip","tag-vista"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p1TKYv-3m","jetpack_sharing_enabled":true,"jetpack-related-posts":[],"_links":{"self":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/208","targetHints":{"allow":["GET"]}}],"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=208"}],"version-history":[{"count":5,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/208\/revisions"}],"predecessor-version":[{"id":213,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/208\/revisions\/213"}],"wp:attachment":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/media?parent=208"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/categories?post=208"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/tags?post=208"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}