{"id":876,"date":"2012-06-06T09:07:57","date_gmt":"2012-06-05T21:07:57","guid":{"rendered":"https:\/\/www.deltics.co.nz\/blog\/?p=876"},"modified":"2012-06-06T13:15:45","modified_gmt":"2012-06-06T01:15:45","slug":"commonest-weakness","status":"publish","type":"post","link":"https:\/\/www.deltics.co.nz\/blog\/posts\/876\/","title":{"rendered":"Commonest Weakness&#8230;"},"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>Stefan Glienke recently added <a href=\"http:\/\/delphisorcery.blogspot.co.nz\/2012\/06\/weak-interface-references.html\">his contribution to the various solutions for implementing weak interface references in Delphi<\/a>.<br \/>\n<!--more--><br \/>\nHe quite neatly and comprehensively covers the need for such things, but his approach requires generics support and so is limited to later versions of the compiler (just how late really depends on how confident you are in the robustness of the generics implementation in each iteration of the Delphi compiler since their introduction).<\/p>\n<p>So I thought I would share my own approach that I have been using for some time and which is usable in all versions of Delphi from 3 (where-in interfaces were introduced).<\/p>\n<p>First, an example of the approach in action using Stefan&#8217;s own example as the basis for my own:<\/p>\n<pre class=\"brush: delphi; title: ; notranslate\" title=\"\">\r\n\r\ntype\r\n  TParent = class(TInterfacedObject, IParent)\r\n  private\r\n    fChildren: TInterfaceList;\r\n    procedure AddChild(const aChild: IChild);\r\n  public\r\n    destructor Destroy; override;\r\n  end;\r\n\r\n  TChild = class(TInterfacedObject, IChild)\r\n  private\r\n    fParentRef: TWeakInterface;\r\n    function get_Parent: IParent;\r\n  public\r\n    constructor Create(const aParent: IParent);\r\n    destructor Destroy; override;\r\n    property Parent: IParent read get_Parent;\r\n  end;\r\n\r\n  \/\/ The implementation of TParent adding a child to it's list\r\n  \/\/  should be sufficiently obvious as to not need illustration\r\n  \/\/  so I shall show only the use of TWeakInterface in TChild\r\n\r\n  constructor TChild.Create(const aParent: IParent);\r\n  begin\r\n    inherited Create;\r\n\r\n    fParentRef := TWeakInterface.Create(aParent);\r\n  end;\r\n\r\n  destructor TChild.Destroy;\r\n  begin\r\n    fParentRef.Free;\r\n    inherited;\r\n  end;\r\n\r\n  function TChild.get_Parent: IParent;\r\n  begin\r\n    result := fParentRef as IParent;\r\n  end;\r\n\r\n<\/pre>\n<p>Since the parent is maintaining strong references to the children (ensuring that as long as the parent survives then it&#8217;s children do also), what we need to take care of (and the whole point of this and Stefan&#8217;s post) is that the children themselves <em>do not hold strong references <strong>back<\/strong> to the parent<\/em>.<\/p>\n<p>I achieve this using a <em>TWeakInterface<\/em>.<\/p>\n<p><em>TWeakInterface<\/em> is essentially an encapsulation of the technique found quite commonly in the VCL itself (as mentioned by Stefano in the comments on Stefan&#8217;s post) of holding an interface reference as a plain pointer value. Stefan rightly points out some dangers of this approach, and the advantage of using an encapsulation such as <em>TWeakInterface<\/em> in this way is that it enables us to address some of these.<\/p>\n<p>With a plain pointer value, the interface it stores is retrieved by hard-casting back to the original interface type:<\/p>\n<pre class=\"brush: delphi; title: ; notranslate\" title=\"\">\r\n\r\n  \/\/ Taking a weak reference from a strong one:\r\n  parentRef := Pointer(someIParent);\r\n\r\n  \/\/ Obtaining a strong reference from a weak one:\r\n  parent := IParent(someIParent);\r\n\r\n<\/pre>\n<p>The potential for mistakes here should be obvious.<\/p>\n<p>When casting the strong reference from the pointer you have to be sure to use the correct interface reference. Use the wrong one (even, for example, an interface that is derived &#8211; i.e. inherits &#8211; from the actual interface reference that is held) and all sorts of things could potentially go wrong.<\/p>\n<p>So one thing that <em>TWeakInterface<\/em> does is treat the encapsulated reference it is provided with as <strong>IUnknown<\/strong> (or <strong>IInterface<\/strong>, if you prefer; Potayto \/ Potahto).<\/p>\n<p>It also does not expose the &#8220;captured&#8221; reference at all.<\/p>\n<p>To get the interface reference back out from <em>TWeakInterface<\/em> you have to ask for it.<\/p>\n<p>Nicely. \ud83d\ude42<\/p>\n<p><em>TWeakInterface<\/em> is itself an interfaced object, but it delegates the entire implementation of <strong>IUnknown<\/strong> to the captured interface reference so that when you write:<\/p>\n<pre class=\"brush: delphi; title: ; notranslate\" title=\"\">\r\n\r\n  result := fParentRef as IParent;\r\n\r\n<\/pre>\n<p>It is the captured interface reference that is asked for the requested interface (<strong>ref.QueryInterface<\/strong>), rather than a hard type-cast being performed.<\/p>\n<p>Thus if you ask for an interface that the weakly referenced object does not support you will get the exception that you so richly deserve.<\/p>\n<p>It also means that you can even ask for an interface that is different from the one you captured, and as long as the referenced object also implements that interface then that also will be fine.<\/p>\n<p>What this approach does not take care of is the situation when the weakly referenced object is destroyed, leaving a &#8220;dangling&#8221; weak reference to itself.<\/p>\n<p>As Stefano points out in his reply to this observation, this situation should not occur when using weak references as the very fact that you *have* this potential means that you should have mechanisms in place to deal with it.<\/p>\n<p>e.g. if a child&#8217;s parent can be destroyed from out above it&#8217;s head, then the child will almost certainly need to know when that happens. <strong>NIL<\/strong>&#8216;ing the reference to it&#8217;s parent is probably the least significant thing it will need to take into account in that situation.<\/p>\n<p>In my own code I have <a href=\"https:\/\/www.deltics.co.nz\/blog\/?p=160\">a multi-cast mechanism available for precisely this &#8220;notify destruction&#8221; purpose<\/a>, and I could easily have incorporated this into my <em>TWeakInterface<\/em> implementation.<\/p>\n<p>That is, in the constructor for <em>TWeakInterface<\/em> it could query the passed interface for <em>IOn_Destroy<\/em> support, and if present add a listener which would <strong>NIL<\/strong> the captured reference when necessary. <em>TWeakInterface<\/em> would then also have to implement <em>IOn_Destroy<\/em>, but that is also a trivial matter.<\/p>\n<p>However, just as Stefano points out, in every instance that this would have been useful, the class incorporating a weak reference to some other object already implements (in my code) an <strong>On_Destroy<\/strong> mechanism for much broader purposes, assuming no other, more direct mechanism exists.<\/p>\n<p>So I decided against incorporating this in my weak interface reference encapsulation itself, keeping it as simple as possible.<\/p>\n<h3>In Summary, The Complete Class<\/h3>\n<pre class=\"brush: delphi; title: ; notranslate\" title=\"\">\r\n\r\n    TWeakInterface = class(TObject)\r\n    private\r\n      fRef: Pointer;\r\n      function get_Ref: IUnknown;\r\n    protected \/\/ IUnknown\r\n      property Ref: IUnknown read get_Ref implements IUnknown;\r\n    public\r\n      constructor Create(const aRef: IUnknown);\r\n    end;\r\n\r\n{ TWeakInterface --------------------------------------------------------------------------------- }\r\n\r\n  { - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - }\r\n  constructor TWeakInterface.Create(const aRef: IUnknown);\r\n  begin\r\n    inherited Create;\r\n\r\n    fRef := Pointer(aRef);\r\n  end;\r\n\r\n  { - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - }\r\n  function TWeakInterface.get_Ref: IUnknown;\r\n  begin\r\n    result := IUnknown(fRef) as IUnknown;\r\n  end;\r\n\r\n<\/pre>\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>Stefan Glienke recently added his contribution to the various solutions for implementing weak interface references in Delphi.<\/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":[29,33,149],"class_list":["post-876","post","type-post","status-publish","format-standard","hentry","category-delphi","tag-interfaces","tag-ion_destroy","tag-weak-references"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p1TKYv-e8","jetpack_sharing_enabled":true,"jetpack-related-posts":[],"_links":{"self":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/876","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=876"}],"version-history":[{"count":14,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/876\/revisions"}],"predecessor-version":[{"id":887,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/876\/revisions\/887"}],"wp:attachment":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/media?parent=876"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/categories?post=876"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/tags?post=876"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}