Qafoo GmbH - passion for software quality ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :Author: Tobias Schlitt :Date: Thu, 16 Oct 2014 07:00:50 +0200 :Revision: 10 :Copyright: All rights reserved ======================== Utilize Dynamic Dispatch ======================== :Description: Dynamic Dispatch is one of the fundamental powers of object oriented programming. By using static access or traits, you throw away this power. :Keywords: object oriented programming, static, trait, dynamic dispatch, php :Abstract: A while ago I replied to the `tweet`__ by `@ramsey`__ Traits are a nice way to provide common functionality to unrelated classes without using static methods on a global Util class. `with`__ Which makes them exactly as evil as static access. Funktionality you dispatch to becomes irreplaceable destroying a fundament of OO: Dynamic dispatch. I want to use this blog post to illustrate the concept of *dynamic dispatch* which I use a lot recently to motivate creating clean OO structures in my trainings. In my experience, this helps people to understand why we want to write code in this way. After that I will show why traits are bad in this direction. __ https://twitter.com/ramsey/status/509028110465908737 __ https://twitter.com/ramsey __ https://twitter.com/tobySen/status/509040311122022400 A while ago I replied to the `tweet`__ by `@ramsey`__ Traits are a nice way to provide common functionality to unrelated classes without using static methods on a global Util class. `with`__ Which makes them exactly as evil as static access. Funktionality you dispatch to becomes irreplaceable destroying a fundament of OO: Dynamic dispatch. __ https://twitter.com/ramsey/status/509028110465908737 __ https://twitter.com/ramsey __ https://twitter.com/tobySen/status/509040311122022400 I want to use this blog post to illustrate the concept of *dynamic dispatch* which I use a lot recently to motivate creating clean OO structures in my trainings. In my experience, this helps people to understand why we want to write code in this way. After that I will show why traits are bad in this direction. Dynamic dispatch is actually an implementation detail of object oriented programming languages. To explain it I need to take a little leap back in time and illustrate the code flow in a classic procedural program: .. image:: /blog/images/072_procedural_dispatch.png :width: 570 :height: 216 :alt: Procedural Dispatch The graphic shows two procedures which call a shared ``log()`` procedure, the arrows visualize the execution flow of the program. As can be seen, a procedural program classically works top down. In order to solve a complex task, a procedure dispatches to other procedures where each fulfills a smaller fraction of the task. It is important to notice that the procedures to be executed are exactly known at compile time of the program (simplified). This is what is called a *static dispatch*. Imagine you now want to log all friendship related operations to the new *Facelog* server, because it generates incredibly useful insights for you. What are your options to implement this change? You can a) change the ``log()`` procedure itself, i.e. patch it. But this is of course no real option here, because ``createUser()`` would also be affected by this change and most probably many other modules that use ``log()``. Option b) is to touch the ``createFriendship()`` procedure (and any other friendship related modules) and change them to use another procedure instead of ``log()``, e.g. ``facelog()``. Following this approach is viable, but also means quite some work and potential for errors. In the object oriented (OO) paradigm the situation is different: .. image:: /blog/images/072_object_oriented_dispatch.png :width: 570 :height: 357 :alt: Object Oriented Dispatch The most obvious difference here is that there are two types of errors: Black arrows visualize the actual code flow again, while gray ones indicate object (actually class) dependencies. The ``UserService`` depends on ``Logger``, ``FileLogger`` extends ``Logger`` and so on. And this exactly is the crucial point: At compile time, an object oriented program typically only knows about the class dependencies. At this stage it is unclear, how the actual execution flow will be at run-time. It depends upon which particular object is given to the dependant, which might be influenced by configuration, user-input and so on. On a technical level, the programming environment decides out of a set of available method implementations which one is the correct one to use. This is what we call *dynamic dispatch*. So how could you perform the required change in this environment? Of course you can just give a different object to ``FriendshipService``, which provides the API defined by the ``Logger`` type but talks to Facelog instead of writing to a file. The dynamic dispatch will take care. The nice thing: You neither need to touch the ``FriendshipService`` nor do you need to fear undesired side-effects on ``UserService`` and others by touching the ``FileLogger``. Now, that is dynamic dispatch: Your execution environment decides at run-time, which method is actually to be called, based on the actual object reference given for a type dependency. There is no need to recompile the program to achieve a change in this dispatching, a different user input or configuration can suffice. Now take a look at a static method call as shown in the following graphic: .. image:: /blog/images/072_oo_static_dispatch.png :width: 570 :height: 245 :alt: Static Class Dispatch What do you realize? Right, a static method call is actually a procedural call. Indeed, the dispatch is static in this case: There is no way for you to replace this call fine grained, except for the two procedural approaches explained further up. Whenever you introduce a static method call, you throw away the powers that dynamic dispatch unveils to you. Now look at the next graphic that shows a trait implementation for the ``Logger``: .. image:: /blog/images/072_oo_trait_dispatch.png :width: 570 :height: 274 :alt: Trait Dispatch Using a trait copies a piece of code into your class, making it a part itself. How would you realize the desired change now? True, there is now way to utilize dynamic dispatch here, but only the procedural approaches work. *A trait is static dispatch, too.* **Disclaimers**: 1. There is of course much more in the background of this very narrow view on object oriented mechanics, for example subtype polymorphism. 2. I'm aware that there are concepts in procedural languages to implement a dynamic dispatch, too, for example function pointers. However, for illustration purposes, it is helpful to take these out of scope here. .. Local Variables: mode: rst fill-column: 79 End: vim: et syn=rst tw=79 Trackbacks ========== Comments ======== - Raman Ghadge at Mon, 11 Jun 2018 12:02:35 +0200 Nice post.