What can we learn about software from an ice cream shop? Quite a bit apparently. It was in the early 70's that Steve's Ice Cream opened and introduced the world to the notion of mix-ins. The idea was simple but powerful. Lets produce a small amount of base ice cream flavors like vanilla, chocolate, and strawberry. Then, the strategy goes, provide a plethora of small independent ingredients to mix in to the base flavor resulting in unending flavor possibilities.
Given the success of this approach and many many other ice cream shops like Cold Stone Creamery and Diary Queen that provide similar services the approach seems almost obvious. Well, many things seem obvious in retrospect.
The idea itself has great merit! I would want to be able to serve the customer who wants their ice cream to be crunchy as well as those that gag at the thought. If they also want (need!) that smooth caramel ribbon that should be no problem. It is relatively easy to provide 4 different ice cream flavors with different combinations of nuts and caramel to appease all customer types, but this becomes a bit harder when we experience the combinatorial explosion of including (or not!) nuts, oreos, sprinkles, gummy bears, peanut butter cups, and on and on. The genius of the mixin approach is the realization that while each of these items on their own does not an ice cream flavor make, when you can independently choose which of them to mix in for a particular customer the ice cream shop owner can be very nimble to adapt to the needs at hand.
Does this resonate with MATLAB? As we strive to keep MATLAB class hierarchies wide the mixin approach can be very attractive. To apply this approach what we need to do is use the various attributes and capabilities that we want to share across many different types of classes or objects and package them up into their own independent mixin class. Such a mixin class should truly have just one purpose or responsibility. The idea is that this is a class which does not have much meaning on its own, much like a walnut does not have much value as an ice cream product on it own. However, when mixed in with other code can provide a rich, yet flexible, software product.
Technically speaking, we already saw this with our first discussion on this theme of flexible inheritance hierarchies. In this example we see the following code:
classdef CelestialBody properties Mass end end classdef(Abstract) Rounded properties Radius end end classdef Asteroid < CelestialBody properties Shape end end classdef Moon < CelestialBody & Rounded properties HostPlanet end end classdef Star < CelestialBody & Rounded methods function radiate(star) end end end classdef Planet < CelestialBody & Rounded properties Moons end end classdef TerrestrialPlanet < Planet properties Crust end end classdef(Abstract) HasRings properties Rings end end classdef GasGiant < Planet & HasRings end classdef IceGiant < Planet & HasRings end
This code produces the wide hierarchy below:
What we didn't really discuss last time was that this is actually inheriting not just interface, but actually implementation from the Rounded and HasRings base classes. This is an alternative to composition which brings both the interface and the implementation to the inheriting class. The key to success here is that the classes intended to be used this way only provide one ability and one ability only. It is an asset of any mixin class that it is not actually useful on its own. In fact, Sam had the right intuition here when he felt like these classes should be abstract. Making them abstract further solidifies their intent, prevents them from being used on their own, and thus prevents the class from becoming bloated with additional content as it evolves. The observant reader will have noticed that the relevant classes are indeed abstract in this version whereas they were not in the earlier post.
So when do we use mixins and when do we use composition? This is an excellent design question indeed and I am a bit uncomfortable providing any guidance at all due to the risk of blind observance to a rule of thumb. The fact is you should be aware of both approaches in your own world of software design. If you tend to fall into the trap of using inheritance for everything and find that you think about code sharing more than the abstraction that the inheritance provides then I would suggest strengthening your use of composition. If you find yourself constantly writing boiler plate code because you are strictly adhering to composition over inheritance for many small interfaces then you definitely want to consider whether mixins are appropriate. They are indeed powerful.
Note well that there is a distinct difference in the type of the resulting object when either of the two approaches are used. When composition is used you can decouple the type of the object from the implementation, whereas the use of mixins you receive the type and the implementation. Sometimes you want the type, like when your client code wants to accept any object that "HasRings" because the notion of Ringed-ness as a concept exists solely within the celestial body code. Sometimes you do not, such as when you want to ensure that celestial body code that operates on rounded celestial bodies rejects basketballs and oranges that also subscribe to Rounded behavior.
MATLAB itself has a few built-in mixin types, like matlab.mixin.Heterogenous, matlab.mixin.Copyable, and matlab.mixin.CustomDisplay. From these examples you can see some of these principles at work. Each of them have broad applicability yet a narrowness of scope. None of them really produce anything intrinsically valuable on their own, but provide a great deal of value when mixed into existing object structures. Have you ever used these mixin classes that are included with MATLAB? If not are you interested in working through some examples of their use? Do you write your own mixin classes in order to leverage the flexibility they provide?
Who ever thought that an ice cream shop would have such a lasting impact on the culture and ethos of software architecture? Actually who am I kidding? Ice cream is awesome, it was always destined for such greatness!
To leave a comment, please click here to sign in to your MathWorks Account or create a new one.