{"id":2511,"date":"2017-02-11T09:53:45","date_gmt":"2017-02-10T21:53:45","guid":{"rendered":"https:\/\/www.deltics.co.nz\/blog\/?p=2511"},"modified":"2017-02-11T11:20:29","modified_gmt":"2017-02-10T23:20:29","slug":"anonymous","status":"publish","type":"post","link":"https:\/\/www.deltics.co.nz\/blog\/posts\/2511\/","title":{"rendered":"Anonymous Classes: Implementing Interfaces"},"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>A few years ago (2011 to be precise) <a href=\"http:\/\/stackoverflow.com\/questions\/6786401\/implement-a-delphi-interface-using-an-anonymous-class\">someone asked a question on StackOverflow about support for anonymous classes in Delph<\/a>i.  The reason for the question was that the poster was trying to use Delphi to develop for Android and on that platform the widespread use of callback interfaces makes anonymous classes <em>highly<\/em> desirable.<\/p>\n<p><!--more--><\/p>\n<p>As far as I know, despite oft repeated claims about how the Delphi language is &#8220;advancing&#8221;, Delphi <em>still<\/em> lacks this useful language feature.  Whilst there may be complex and contorted ways to contrive anonymity (as illustrated in the answer to that StackOverflow question) it is much more convenient to have the language support the ability to conjure an anonymous class as and when needed without having to provide all that scaffolding (or to be precise: to have the compiler take care of the scaffolding for you behind the scenes).<\/p>\n<p>Needless to say, Oxygene does this with aplomb (and did so even back in 2011).<\/p>\n<p>Let&#8217;s look at a very simple example: Connecting to a <a href=\"https:\/\/developers.google.com\/android\/reference\/com\/google\/android\/gms\/common\/api\/GoogleApiClient\">GoogleApiClient<\/a>.<\/p>\n<h2>GoogleApiClient.ConnectionCallbacks<\/h2>\n<p>As the hub for a wide range of Google Api&#8217;s this is a common task and connecting to the Api client involves handling a number of different callbacks.  All of these callbacks are provided to the Api client by supplying implementations of those callbacks as specified in interfaces.<\/p>\n<p>In our example scenario we have an activity which is connecting to the Api client (among other things) and it seems obvious at first to simply declare and implement the required callback interfaces directly on the activity itself:<\/p>\n<pre class=\"brush: oxygene; title: ; notranslate\" title=\"\">\r\nMainActivity = public class(AppCompatActivity, View.OnClickListener,\r\n                                               OnMapReadyCallback, \r\n                                               GoogleApiClient.ConnectionCallbacks,\r\n                                               GoogleApiClient.OnConnectionFailedListener,\r\n                                               LocationListener,\r\n                                               ServiceConnection)\r\nprivate\r\n  fGoogleApis: GoogleApiClient;\r\npublic\r\n  method onCreate(savedInstanceState: Bundle); override;\r\n\r\n  \/\/ .. etc ..\r\n\r\npublic \/\/ -- Interfaces\r\n  \/\/ GoogleApiClient.ConnectionCallbacks\r\n  method onConnected(theHint: Bundle);\r\n  method onConnectionSuspended(theCause: Integer);\r\n\r\n  \/\/ GoogleApiClient.OnConnectionFailedListener\r\n  method onConnectionFailed(theResult: ConnectionResult); \r\nend;\r\n<\/pre>\n<p>This activity is not only providing callbacks for the Google Api Client but also for other things such as Google Maps notifications, Location Services updates, UI View click responses and even Service bindings.<\/p>\n<p>The broader details of all of these interfaces aren&#8217;t important, neither are the more general details of the <strong>MainActivity<\/strong> in this case.  What is important is that as we add more capabilities to our activity we can see how the number of interfaces being implemented can increase quite rapidly and, although it&#8217;s not shown, this also can result in a large number of methods on the activity, simply to satisfy those interfaces.<\/p>\n<p>In many cases the response to a particular callback is local to the point at which the callback is provided or simply provides a &#8220;hook&#8221; to respond to a callback to invoke more complex processing in our activity that is also invoked in other situations.<\/p>\n<p><strong>The result:<\/strong>  A great deal of noise in our activity, &#8216;polluting&#8217; the class and making it difficult to separate the real function of the activity from the scaffolding.<\/p>\n<p>Anonymous classes help us address that by avoiding the need to encumber the activity with these details.<\/p>\n<p>First, let&#8217;s back up a little and look at how we register the Api client callback interfaces when we configure our client, typically in the <strong>onCreate<\/strong> method of our activity:<\/p>\n<pre class=\"brush: oxygene; title: ; notranslate\" title=\"\">\r\n\r\n  method MainActivity.onCreate(savedInstanceState: Bundle);\r\n  begin\r\n    inherited onCreate(savedInstanceState);\r\n\r\n    \/\/ ..\r\n\r\n    fGoogleApis := new GoogleApiClient.Builder(self)\r\n      .addConnectionCallbacks(self)\r\n      .addOnConnectionFailedListener(self)\r\n      .addApi(Auth.GOOGLE_SIGN_IN_API, gso)\r\n      .addApi(LocationServices.API)\r\n      .build;\r\n\r\n    \/\/ ..    \r\n  end;\r\n\r\n<\/pre>\n<p>We use a <strong>GoogleApiClient<\/strong> builder to setup our Api client and register the <strong>MainActivity<\/strong> (<em>self<\/em>) as the provider of the connection callbacks.<\/p>\n<p>There are two separate callback interfaces involved here, but we&#8217;ll focus on the first (<strong>addConnectionCallbacks()<\/strong>)as this is the more complex of the two, requiring the implementation of two methods as opposed to just one.<\/p>\n<h2> An Anonmyous Class to Implement a Callback Interface <\/h2>\n<p>Instead of providing a reference to the <strong>MainActivity<\/strong> as the implementer of the <strong>GoogleApiClient.ConnectionCallbacks<\/strong> interface, we can provide an <em>inline<\/em> implementation of that interface without having to declare a formal class but using an anonymous class instead.<\/p>\n<p>The first step is to instantiate an anonymous class implementing the required interface.  We will use this in place of the reference to <em>self<\/em> when we registered the callbacks with <strong>addConnectionCallbacks<\/strong>.<\/p>\n<p>To instantiate an anonymous class we invoke <strong>new<\/strong> with the <strong>interface<\/strong> to identify the interface to be implemented on the anonymous class:<\/p>\n<pre class=\"brush: oxygene; title: ; notranslate\" title=\"\">\r\n\r\n    .addConnectionCallbacks(new interface GoogleApiClient.ConnectionCallbacks());\r\n\r\n<\/pre>\n<p>But of course we also need to provide an <em>implementation<\/em> for the interface.<\/p>\n<p>To do that we identify the implementation associated with each function by assigning a method body to the required interface member:<\/p>\n<pre class=\"brush: oxygene; title: ; notranslate\" title=\"\">\r\n\r\n    .addConnectionCallbacks\r\n    (\r\n      new interface GoogleApiClient.ConnectionCallbacks\r\n      (\r\n        onConnected := method(hint: Bundle)\r\n        begin\r\n          \/\/ What we do when we're connected to the Api client\r\n        end,\r\n\r\n        onConnectionSuspended := method(cause: Integer)\r\n        begin\r\n          \/\/ What we do when our Api client connection is suspended\r\n        end;\r\n      )\r\n    )\r\n\r\n<\/pre>\n<p>Obviously the way I have formatted the parenthesis blocks here is a purely personal preference.  You might prefer an alternate approach.<\/p>\n<p>This approach of assigning values (in this case method bodies) to members of a class directly in the constructor is not unique to anonymous classes.  It is the same pattern that is supported more generally in Oxygene to add in-line initialization of members on a new instance immediately following any required constructor parameters.<\/p>\n<p>In the case of anonymous classes of course there is only the default, parameterless constructor, so the additional initialization consists entirely of member method body assignments.<\/p>\n<h2> Cleaning Up the Activity <\/h2>\n<p>Having implemented the callbacks in this way we can now dramatically simplify our activity class:<\/p>\n<pre class=\"brush: oxygene; title: ; notranslate\" title=\"\">\r\nMainActivity = public class(AppCompatActivity, View.OnClickListener,\r\n                                               OnMapReadyCallback,\r\n                                               LocationListener,\r\n                                               ServiceConnection)\r\nprivate\r\n  fGoogleApis: GoogleApiClient;\r\npublic\r\n  method onCreate(savedInstanceState: Bundle); override;\r\n\r\n  \/\/ .. etc ..\r\nend;\r\n<\/pre>\n<p>All that scaffolding to take care of implementing a few callbacks is swept away and obviously we could reduce it even further in this case if we took the same approach with those other callback interfaces still present.<\/p>\n<p>Which isn&#8217;t to say that you would <em>never<\/em> choose to implement a callback interface directly on an activity or other formal class type defined for the purpose.<\/p>\n<p>In some cases it might still make most sense to do so for a particular interface.  But with anonymous classes in your toolbox this becomes a deliberate <em>choice<\/em> rather than your only option.<\/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> A few years ago (2011 to be precise) someone asked a question on StackOverflow about support for anonymous classes in Delphi. The reason for the question was that the poster was trying to use Delphi to develop for Android and on that platform the widespread use of callback interfaces makes anonymous classes highly desirable.<\/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":[212,205,4,180],"tags":[153,311,13,173],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p1TKYv-Ev","jetpack_sharing_enabled":true,"jetpack-related-posts":[{"id":48,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/48\/","url_meta":{"origin":2511,"position":0},"title":"Anonymous Methods &#8211; When Should They Be Used?","date":"04 Aug 2008","format":false,"excerpt":"Explores the relevance of authorities supposed to be making a good case for anonymous methods","rel":"","context":"In &quot;Delphi&quot;","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":1817,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/1817\/","url_meta":{"origin":2511,"position":1},"title":"Getting the Battery Level on Android With Delphi","date":"01 Oct 2013","format":false,"excerpt":"Over the past few days I posted a two part series showing how to obtain the current battery level as part of the implementation of an Android AppWidget using Oxygene. As far as I can tell AppWidgets simply aren't possible using Delphi but reading the battery is quite straightforward Android\u2026","rel":"","context":"In &quot;Android&quot;","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":2006,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/2006\/","url_meta":{"origin":2511,"position":2},"title":"Blowing Smoke&#8230;","date":"01 Nov 2013","format":false,"excerpt":"To alleviate the grind of polishing and sanitising my code (and, let's be honest, just plain 'fixing' it in some cases) ready for release, I have re-kindled my participation on Stack Overflow. In a happy confluence yesterday a question came up which allowed me to exercise one of the libraries\u2026","rel":"","context":"In &quot;Delphi&quot;","img":{"alt_text":"Ready to Run","src":"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2013-11-01-at-09.00.33.png?resize=350%2C200&ssl=1","width":350,"height":200},"classes":[]},{"id":507,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/507\/","url_meta":{"origin":2511,"position":3},"title":"Mind the Gap(s)","date":"14 Sep 2009","format":false,"excerpt":"This is what I love about Delphi. \u00a0After almost 15 years of Delphi'ing there's still new things to learn, and I don'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\u2026","rel":"","context":"In &quot;Delphi&quot;","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":2353,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/2353\/","url_meta":{"origin":2511,"position":4},"title":"Formatting Case Statements","date":"14 Aug 2015","format":false,"excerpt":"I'm afraid I have been guilty of editorialising on StackOverflow. It was sheer laziness really. A question prompted me to respond by sharing a personal preference and instead of \"context switching\" to my blog I posted an answer that even at the time I acknowledged was not in fact an\u2026","rel":"","context":"In &quot;Delphi&quot;","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":582,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/582\/","url_meta":{"origin":2511,"position":5},"title":"On the Qt and all very Hush, Hush&#8230;","date":"14 Oct 2009","format":false,"excerpt":"A commenter on my blog suggested that Cross Platform could be a big win for Delphi, making it \u201cthe first\u201d to achieve this. \u00a0This I think says a lot about the awareness and expectation of (some) of the people asking for cross platform, because far from being first Delphi would\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\/2511"}],"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=2511"}],"version-history":[{"count":10,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/2511\/revisions"}],"predecessor-version":[{"id":2521,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/2511\/revisions\/2521"}],"wp:attachment":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/media?parent=2511"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/categories?post=2511"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/tags?post=2511"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}