{"id":1213,"date":"2021-07-07T10:05:00","date_gmt":"2021-07-07T16:05:00","guid":{"rendered":"https:\/\/www.great-white-software.com\/blog\/?p=1213"},"modified":"2021-07-06T19:53:20","modified_gmt":"2021-07-07T01:53:20","slug":"coincidence","status":"publish","type":"post","link":"https:\/\/www.great-white-software.com\/blog\/2021\/07\/07\/coincidence\/","title":{"rendered":"Coincidence"},"content":{"rendered":"\n<p>Sometimes you want classes to have a common API. <\/p>\n\n\n\n<p>But rather than adding a common super class or interface to define that common API, you just make sure your classes have the same methods, events, properties &amp; whatever else you feel is necessary to make them have &#8220;the same API&#8221;.<\/p>\n\n\n\n<p>I would suggest you rethink doing this.<\/p>\n\n\n\n<p>If what you need is controls that are similar but have differences in them just making it so you have common methods names, properties, and events will make trying to write any common code that can manipulate these controls a pain in the read end to create, maintain, and update.<\/p>\n\n\n\n<p>For instance, lets suppose we create two controls that do wildly different things. One is a canvas control subclass that draws itself in whatever color set with a blue frame. The other draws the frame in in red. (This example is exceeding simple just to illustrate the issues. Its worse with more complex classes &amp; controls)<\/p>\n\n\n\n<p>So we have <\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Class BlueCanvas\n  Inherits Canvas\n\n  property myfillColor as color\n\n  Sub SetFill(newFillColor as Color)\n     myfillcolor = newFillColor\n  End Sub\n\n  Function GetFill() as Color\n     return myfillColor\n  End Function\n\n  Event Paint(g as graphics, areas() as \n     g.forecolor = myfillColor\n     g.fillrect 0,0, g.width, g.height\n\n     g.forecolor = &amp;c0000FF\n     g.drawrect 0,0, g.width, g.height\n  End event\nEnd Class\n\nClass RedCanvas\n  Inherits Canvas\n\n  property myfillColor as color\n\n  Sub SetFill(newFillColor as Color)\n     myfillcolor = newFillColor\n  End Sub\n\n  Function GetFill() as Color\n     return myfillColor\n  End Function\n\n  Event Paint(g as graphics, areas() as \n     g.forecolor = myfillColor\n     g.fillrect 0,0, g.width, g.height\n\n     g.forecolor = &amp;cFF0000\n     g.drawrect 0,0, g.width, g.height\n  End event\nEnd Class\n<\/code><\/pre>\n\n\n\n<p>So our two controls have &#8220;the same API&#8221;<\/p>\n\n\n\n<p>Same events, same methods, same properties of the same type &amp; name.<\/p>\n\n\n\n<p>Lets see what happens when we try to write code that uses these two simple controls.<\/p>\n\n\n\n<p>Suppose we&#8217;d like to write a single method that can change the fillcolor of either control<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Sub AlterFillColor(ctrl as Variant)\n\n   Dim c As Color \n\n   If SelectColor(c,\"select a color\") Then\n  \n    If ctrl IsA BlueCanvas Then\n      BlueCanvas(ctrl).myFillColor = c\n      BlueCanvas(ctrl).Invalidate\n    Elseif ctrl IsA RedCanvas Then\n      RedCanvas(ctrl).myFillColor = c\n      RedCanvas(ctrl).Invalidate\n    End If\n  \nEnd If\n<\/code><\/pre>\n\n\n\n<p>Note several things. The parameter passed in has to be something generic &#8211; but it cant be a BlueControl or a RedControl as there is nothing really common between them. We could pass a Canvas but that would not change the code in actual method.<\/p>\n\n\n\n<p>We MUST check to see, in this case, exactly what type was passed in because we cant be sure an appropriate type was passed in. Even if we used a Canvas we&#8217;d have to check because a generic Canvas may not have the myFillColor property and trying to access that would cause compilation errors. If we use Variant anything can be passed in. If we make that parameter an Object any INSTANCE of ANY class, not JUST our labels, can be passed  in.<\/p>\n\n\n\n<p>We MUST cast, either one time and assign to a temporary we reuse , or on every line of code where we use the control.<\/p>\n\n\n\n<p>And this is one VERY short method and it already looks messy.<\/p>\n\n\n\n<p>How about adding a button to copy the value of myFillColor from one canvas to another.<\/p>\n\n\n\n<p>If we add one button to copy from the bluecanvas to the redcanvas, and another to copy the other way we can copy directly from one to another using something like :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>RedCanvas1.SetFill( BlueCanvas1.GetFill() )<\/code><\/pre>\n\n\n\n<p>or<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>BlueCanvas1.SetFill( RedCanvas1.GetFill() )<\/code><\/pre>\n\n\n\n<p>This isnt so bad. But, being the clever sort we are we decide to write a generic &#8220;copy from one to the other&#8221; method and reuse the heck out of it  (and this is where your spidey sense should really go crazy !)<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Public Sub CopyFill(fromCtrl as variant, toCtrl as Variant)\n\n  Dim copycolor As Color\n\n  If fromCtrl IsA BlueCanvas Then\n    copycolor = bluecanvas(fromctrl).FillColor\n  Elseif fromCtrl IsA redCanvas Then\n    copycolor = redcanvas(fromctrl).FillColor\n  End If\n\n  If toCtrl IsA BlueCanvas Then\n    bluecanvas(toCtrl).FillColor = copycolor\n  Elseif toCtrl IsA redCanvas Then\n    redcanvas(toCtrl).FillColor = copyColor\n  End If\n  \nEnd Sub\n<\/code><\/pre>\n\n\n\n<p>And from the outset we have the same issue as above<\/p>\n\n\n\n<p>Except now to manipulate two items we need to do several checks to see what types the from and to controls are.<\/p>\n\n\n\n<p>So despite these &#8220;having the same API&#8221; thats of no real value since you have to cast and check all the time. And your parameters to methods have to be some more generic type like variant or some common super that still leaves you needing to cast all the time.<\/p>\n\n\n\n<p>Worst of all you can pass ANY parameter that is of the right type. The compiler cannot help you check that your code is correct since it cant do type checking.<\/p>\n\n\n\n<p>Now what if we decide we want to add a &#8230; YellowCanvas !<\/p>\n\n\n\n<p>You can go back and see for yourself how many places we have to adjust to handle this &#8220;new&#8221; type. Every place we have a cast is a potential place we need to add code to. <\/p>\n\n\n\n<p>And every place we add code is a new place for new bugs to crop up.<\/p>\n\n\n\n<p>So how can we solve this in our little example ? I&#8217;m sure many of you have already seen the answer. In this case an interface ISNT of use since we can&#8217;t define events and properties. <\/p>\n\n\n\n<p>But a common base class, even one that CANNOT be created directly, is of use.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Class FramedCanvas\n  Inherits Canvas\n\n property myfillColor as color\n\n  Sub SetFill(newFillColor as Color)\n     myfillcolor = newFillColor\n  End Sub\n\n  Function GetFill() as Color\n     return myfillColor\n  End Function\n\n  Private Sub Constructor()\n    \/\/ makes it so you cant place instances on a layout\n    \/\/ or create them direcly\n  End Sub\n\nEnd Class\n\nClass BlueCanvas\n  Inherits FramedCanvas\n\n  Event Paint(g as graphics, areas() as \n     g.forecolor = myfillColor\n     g.fillrect 0,0, g.width, g.height\n\n     g.forecolor = &amp;c0000FF\n     g.drawrect 0,0, g.width, g.height\n  End event\nEnd Class\n\nClass RedCanvas\n  Inherits FramedCanvas\n  \n  Event Paint(g as graphics, areas() as \n     g.forecolor = myfillColor\n     g.fillrect 0,0, g.width, g.height\n\n     g.forecolor = &amp;cFF0000\n     g.drawrect 0,0, g.width, g.height\n  End event\nEnd Class<\/code><\/pre>\n\n\n\n<p>Now our classes dont just have the same API because we happened to write them that way. They have the same API by definition. They cant NOT have the same API.<\/p>\n\n\n\n<p>Now our method to set a fillColor looks like<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Public Sub AlterFillColor(ctrl as FramedCanvas)\n  Dim c As Color \n  \n  If SelectColor(c,\"select a color\") Then\n    \n    ctrl.FillColor = c\n    ctrl.Invalidate\n  End If\n  \nEnd Sub\n<\/code><\/pre>\n\n\n\n<p>Note we CAN use the super class as the TYPE for the parameter. BlueCanvases are also FramedCanvases. As are RedCanvases. But a regular canvas control could NOT be passed in (unlike before) and we do not need to do any casting etc. The compiler CAN check for us what is passed in. So our reliability and likelihood of writing bug free code is improved.<\/p>\n\n\n\n<p>And, note, we have LESS code than before. And even if we add YellowCanvases etc we do NOT need to alter this code. Thats a good thing.<\/p>\n\n\n\n<p>Directly copying the fill color from one control to another still works about the same<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>BlueCanvas1.SetFill( RedCanvas1.GetFill() )\nBlueCanvas1.Invalidate<\/code><\/pre>\n\n\n<p>or<\/p>\n\n\n<pre class=\"wp-block-code\"><code>RedCanvas1.SetFill( BlueCanvas1.GetFill() )\nRedCanvas1.Invalidate\n<\/code><\/pre>\n\n\n\n<p>What about our method based copy that we want to just reuse like mad ?<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Public Sub CopyFill(fromCtrl as FramedCanvas, toCtrl as FramedCanvas)\n  toCtrl.FillColor = fromCtrl.fillColor \nEnd Sub\n<\/code><\/pre>\n\n\n\n<p>Its trivial. No casts. No need to alter it every time a new sub type of framedCanvas comes along. And unlikely to ever have a bug.<\/p>\n\n\n\n<p>Why ? Because these controls have an EXPLICIT API that forces them to be the same. Its not just because I happened to write the same code in several of them but because BY DEFINITION they are the same.<\/p>\n\n\n\n<p>Where&#8217;s this all leading ? <br>Well so far this has all been simple and in a desktop app. It could just as well have been in a web app, iOS or some other app type. But the PRINCIPLES hold true even if you wanted to extend this to be across all those app types.<\/p>\n\n\n\n<p>Suppose the hierarchy defined was<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>  Control\n     - common control events, method &amp; properties\n\n     RectControl\n         - common rect control events, method &amp; properties \n           (for controls bound by a bounding box)\n         Button\n            - common button events properties &amp; methods\n            DesktopButton\n               - events properties &amp; methods specific to the desktop\n            WebButton\n               - events properties &amp; methods specific to the web\n            iOSButton\n               - events properties &amp; methods specific to ios            \n         Canvas\n         Listbox\n         TabPanel\n         PagePanel<\/code><\/pre>\n\n\n\n<p>and so on<\/p>\n\n\n\n<p>Now its plausible to write a method that regardless of whether it was used in a desktop, ios, or web project that could locate a Control, Rectcontrol, or Button. Or any other control that is defined.<\/p>\n\n\n\n<p>No casting required.<\/p>\n\n\n\n<p>There are some compatibility details. The DesktopButton would have to have its flags set to only be in desktop projects, the web ones only in web projects, etc. That would solve trying to compile a desktop project with iOS or web controls &amp; vice versa.<\/p>\n\n\n\n<p>The same may be true for controls that only exist on the desktop, and have no counter parts elsewhere. But those flags can be set at any level in the hierarchy.<\/p>\n\n\n\n<p>And the IDE could check those flags to see what things ARE compatible and not allow you to use ones that arent.<\/p>\n\n\n\n<p>The other upside with a properly laid out hierarchy like this for EVERYTHING is that it BY DEFINITION it tells you what properties you could expect to carry over if you copied a desktop button and pasted it into a web project. Nothing that is desktop specific should, or could, make sense in the web one. But anything defined in BUTTON and higher up in the hierarchy would, or should, be able to be copied over to a web button when you paste.<\/p>\n\n\n\n<p>Currently its hard for any of us to do this in a cross platform app that targets ios, web and desktop simply because the underlying items in the frameworks do not do this already. <\/p>\n\n\n\n<p>And the IDE doesnt seem to sort things out right. Depending on what version of the IDE you  use you might see in the example SameXPLATExplicitAPI that the Blue Canvas has its compat flags all off but thats really wrong since it SHOULD be compatible with desktop. It would be subclassed from the Desktop one. And using those modules on ios would be from the IOS one. And on web from the web one. But this doesnt work as I expect. In some versions they are all greyed out and things &#8220;run&#8221; but the paint events never get called \ud83d\ude41<\/p>\n\n\n\n<p>So trying to make a FramedCanvas, like above, that works in iOS, desktop, and web IS, at the moment, not possible.<\/p>\n\n\n\n<p>Making it so things share as much of their API by DEFINITION rather than just by coincidence would make it so more code is, or can be, cross platform without needing to copy paste from project to project.<\/p>\n\n\n\n<p>Imagine THAT world ! <\/p>\n\n\n\n<p><\/p>\n\n\n\n<p><a href=\"http:\/\/great-white-software.com\/miscellaneous\/APICoincidences.zip\">Examples<\/a><\/p>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Sometimes you want classes to have a common API. But rather than adding a common super class or interface to define that common API, you just make sure your classes have the same methods, events, properties &amp; whatever else you feel is necessary to make them have &#8220;the same API&#8221;. I would suggest you rethink &hellip; <\/p>\n<p class=\"link-more\"><a href=\"https:\/\/www.great-white-software.com\/blog\/2021\/07\/07\/coincidence\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;Coincidence&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[1],"tags":[],"class_list":["post-1213","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/www.great-white-software.com\/blog\/wp-json\/wp\/v2\/posts\/1213","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.great-white-software.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.great-white-software.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.great-white-software.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.great-white-software.com\/blog\/wp-json\/wp\/v2\/comments?post=1213"}],"version-history":[{"count":5,"href":"https:\/\/www.great-white-software.com\/blog\/wp-json\/wp\/v2\/posts\/1213\/revisions"}],"predecessor-version":[{"id":1218,"href":"https:\/\/www.great-white-software.com\/blog\/wp-json\/wp\/v2\/posts\/1213\/revisions\/1218"}],"wp:attachment":[{"href":"https:\/\/www.great-white-software.com\/blog\/wp-json\/wp\/v2\/media?parent=1213"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.great-white-software.com\/blog\/wp-json\/wp\/v2\/categories?post=1213"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.great-white-software.com\/blog\/wp-json\/wp\/v2\/tags?post=1213"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}