One common drawback of using composition instead of inheritance is that methods being provided by individual components may have to be implemented in the derived type, even if they are only
forwarding methods (this is true in most programming languages, but not all; see ). In contrast, inheritance does not require all of the base class's methods to be re-implemented within the derived class. Rather, the derived class only needs to implement (override) the methods having different behavior than the base class methods. This can require significantly less programming effort if the base class contains many methods providing default behavior and only a few of them need to be overridden within the derived class. Thus, the pattern of "composition over inheritance" should not be interpreted as a literal mantra or law, but rather a selectively applicable suggestion to be used where appropriate. For example, in the C# code below, the variables and methods of the base class are inherited by the and derived subclasses. Only the method needs to be implemented (specialized) by each derived subclass. The other methods are implemented by the base class itself, and are shared by all of its derived subclasses; they do not need to be re-implemented (overridden) or even mentioned in the subclass definitions. // Base class public abstract class Employee { // Properties protected string Name { get; set; } protected int ID { get; set; } protected decimal PayRate { get; set; } protected int HoursWorked { get; } // Get pay for the current pay period public abstract decimal Pay(); } // Derived subclass public class HourlyEmployee : Employee { // Get pay for the current pay period public override decimal Pay() { // Time worked is in hours return HoursWorked * PayRate; } } // Derived subclass public class SalariedEmployee : Employee { // Get pay for the current pay period public override decimal Pay() { // Pay rate is annual salary instead of hourly rate return HoursWorked * PayRate / 2087; } }
Avoiding drawbacks This drawback can be avoided by using
traits,
mixins, (type)
embedding, or
protocol extensions. Some languages provide specific means to mitigate this: •
C# provides default interface methods since version 8.0 which allows to define body to interface member. •
C++ allows virtual methods (for specifying a
virtual function) to have default implementations. •
D provides an explicit "alias this" declaration within a type can forward into it every method and member of another contained type. •
Dart provides mixins with default implementations that can be shared. •
Go type embedding avoids the need for forwarding methods. •
Java provides default interface methods since version 8. supports delegation using the annotation on the field, instead of copying and maintaining the names and types of all the methods from the delegated field. •
Julia macros can be used to generate forwarding methods. Several implementations exist such as Lazy.jl and TypedDelegation.jl. •
Kotlin includes the delegation pattern in the language syntax. •
PHP supports
traits, since PHP 5.4. •
Raku provides a trait to facilitate method forwarding. •
Rust provides traits with default implementations. •
Scala (since version 3) provides an "export" clause to define aliases for selected members of an object. •
Swift extensions can be used to define a default implementation of a protocol on the protocol itself, rather than within an individual type's implementation. ==Empirical studies==