Mixins or traits are a third alternative to inheritance or composition. Whether they are better often depends on the particular implementation. The important feature of mixins or traits are that they are like abstract classes, but can be applied to multiple classes (and one class can consume multiple mixins). There are – in some implementations – some details regarding the method resolution order that are different between abstract classes and mixins, but otherwise from that they really are equivalent, up to the point that this difference is irrelevant if the language allows multiple inheritance (MI).
The thing where traits are really great is that they supply zero or more methods, and require zero or more methods. This makes using traits fairly straightforward. However, most languages don't have namespaces for methods – all definitions land in the same namespaces, which can lead to clashes between traits.
Your example doesn't even go that far, because your mixin only implicitly declares the requirements on using classes (that
freshness_threshold must be a date, and
@content must have a
created_at field which must be a date). This is even worse than an abstract class in, say, Java – except that Java doesn't have MI, so you are forced to use composition when “inheriting” multiple behaviours.
In contrast, composition forces you to be more explicit about data flow. This is good, because your code becomes more obvious! In your particular example, the mixin only has a single method, so for all purposes it's equivalent to a free function (or
Proc or whatever it's called in Ruby). This function requires two inputs: the
freshness_threshold date, and the
created_at date. Given such a free function
is_new(creation_date, threshold_date), it is now very simple to make this behaviour avaiable to your classes without having to pollute the public interface of these objects with a public
freshness_threshold date. E.g. they could define
t = Time.now
return is_new(@content.created_at, Time.new(t.year, t.month))
If your objects depend on
is_new as an explicit dependency, e.g.:
def initialize(content, is_new = is_new_default)
@content = content
@is_new = is_new
, then an important advantage of composition appears: we can dynamically supply a different implementation (without having to resort to reflection or similar), which allows us to easily and separately test both the
is_new operation and the code that depends on this operation. This advantage is less obvious for a simple comparison as here or other “functionally pure” operations, but will be truly important if the dependency supplies external side effects, e.g. network requests, database queries, …. Unless the language has dependency management baked-in to the inheritance system or mixin system, this is hard to beat.
Magazines were both used in a polymorphic context where you'd need to find out whether they are
new? without knowing if they are a
Book or a
Magazine, then defining a common interface that declares this method would be sensible (assuming a more statically typed language). However, interface inheritance is completely orthogonal to the inheritance vs. composition discussion.