Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mixins vs composition in scala

In java world (more precisely if you have no multiple inheritance/mixins) the rule of thumb is quite simple: "Favor object composition over class inheritance".

I'd like to know if/how it is changed if you also consider mixins, especially in scala?
Are mixins considered a way of multiple inheritance, or more class composition?
Is there also a "Favor object composition over class composition" (or the other way around) guideline?

I've seen quite some examples when people use (or abuse) mixins when object composition could also do the job and I'm not always sure which one is better. It seems to me that you can achieve quite similar things with them, but there are some differences also, some examples:

  • visibility - with mixins everything becomes part of the public api, which is not the case with composition.
  • verbosity - in most cases mixins are less verbose and a bit easier to use, but it's not always the case (e.g. if you also use self types in complex hierarchies)

I know the short answer is "It depends", but probably there are some typical situation when this or that is better.

Some examples of guidelines I could come up with so far (assuming I have two traits A and B and A wants to use some methods from B):

  • If you want to extend the API of A with the methods from B then mixins, otherwise composition. But it does not help if the class/instance that I'm creating is not part of a public API.
  • If you want to use some patterns that need mixins (e.g. Stackable Trait Pattern) then it's an easy decision.
  • If you have circular dependencies then mixins with self types can help. (I try to avoid this situation, but it's not always easy)
  • If you want some dynamic, runtime decisions how to do the composition then object composition.

In many cases mixins seem to be easier (and/or less verbose), but I'm quite sure they also have some pitfalls, like the "God class" and others described in two artima articles: part 1, part 2 (BTW it seems to me that most of the other problems are not relevant/not so serious for scala).

Do you have more hints like these?

like image 555
Sandor Murakozi Avatar asked Aug 06 '10 09:08

Sandor Murakozi


People also ask

Is mixins a composition?

What are Mixins? Mixins are a form of object composition, where component features get mixed into a composite object so that properties of each mixin become properties of the composite object.

What are mixins in scala?

In scala, trait mixins means you can extend any number of traits with a class or abstract class. You can extend only traits or combination of traits and class or traits and abstract class. It is necessary to maintain order of mixins otherwise compiler throws an error.

Is mixin composition or inheritance?

“Composition” is a general term for any mixing of behaviour from two entities. Mixins as described above is a form of composition. Functional composition is another.

What is the difference between a mixin and inheritance?

Mixins are sometimes described as being "included" rather than "inherited". In short, the key difference from an inheritance is that mix-ins does NOT need to have a "is-a" relationship like in inheritance. From the implementation point of view, you can think it as an interface with implementations.


1 Answers

A lot of the problems that people have with mix-ins can be averted in Scala if you only mix-in abstract traits into your class definitions, and then mix in the corresponding concrete traits at object instantiation time. For instance

trait Locking{    // abstract locking trait, many possible definitions    protected def lock(body: =>A):A }  class MyService{    this:Locking => }  //For this time, we'll use a java.util.concurrent lock val myService:MyService = new MyService with JDK15Locking  

This construct has several things to recommend it. First, it prevents there from being an explosion of classes as different combinations of trait functionalities are needed. Second, it allows for easy testing, as one can create and mix-in "do-nothing" concrete traits, similar to mock objects. Finally, we've completely hidden the locking trait used, and even that locking is going on, from consumers of our service.

Since we've gotten past most of the claimed drawbacks of mix-ins, we're still left with a tradeoff between mix-in and composition. For myself, I normally make the decision based on whether a hypothetical delegate object would be entirely encapsulated by the containing object, or whether it could potentially be shared and have a lifecycle of its own. Locking provides a good example of entirely encapsulated delegates. If your class uses a lock object to manage concurrent access to its internal state, that lock is entirely controlled by the containing object, and neither it nor its operations are advertised as part of the class's public interface. For entirely encapsulated functionality like this, I go with mix-ins. For something shared, like a datasource, use composition.

like image 74
Dave Griffith Avatar answered Oct 03 '22 07:10

Dave Griffith