Object composition

In computer science, composition is a way to combine simple objects or data types into more complex ones. Composited objects are called fields, items, members, and attributes, and the resulting composition a structure or record. The terms usually varies across languages. Members are often named so that each member is distinguished from the others.

Composition is contrasted with subtyping, which is the process of adding detail to a general data type to create a more specific data type. In composition, the composite type "has an" object of a simpler type, while in subtyping, the subtype "is an" instance of its parent type. Composition does not form a subtype but a new type.

Compositions are a critical building block of many basic data structures, including the tagged union, the linked list, the binary tree, and the object used in object-oriented programming.

Sometimes an issue of ownership arises: when a composited object is destroyed, should objects belonging to it be destroyed as well? If not, the case is sometimes called aggregation. For more, see aggregation section below.

In UML, composition is depicted as a filled diamond. It always implies a multiplicity of 1, as only one object at a time can have lifetime responsibility for another object. The more general composition is depicted as an un-filled diamond.

Contents

Recursive composition

Objects can be composited recursively. This requies the use of recursive types or references. Consider a tree. Each node in a tree may be a branch or leaf; in other words, each node is a tree at the same time when it belongs to another tree.

One implementation for the recursive composition is to let each object to have references to others of of the same type. In C, for example, a binary tree can be defined like:

 struct btree {
   struct btree *left, *right;
 }
 

If pointers left and right are valid, the node is thought to be a branch refering to each tree to which left and right point. If not, the node is a leaf. In this way, the recursion can be terminated.

Another is to use a tagged union. See tagged union for an example.

Example

This is an example of composition in C.

typedef struct {
   int age;
   char *name;
   enum { male, female } sex;
 } Person;
 

In this example, the primitive types int, char *, and enum {male, female} are combined to form the composite type of Person. Each object of type Person then "has an" age, name, and sex.

If a Person type were instead created by subtyping, it might be a subtype of Object, and it could inherit some attributes from Object (every object has an age), while extending the definition of Object with new attributes (not every object has a sex, but every person does).

Composition in various languages

C calls a record a struct or structure; object-oriented languages such as Java, Smalltalk, and C++ often keep their records hidden inside objects (class instances); languages in the ML family simply call them records. COBOL was the first programming language to support records directly; Algol got it from COBOL, and Pascal got it, more or less indirectly, from Algol.

C/C++

A struct is the C programming language's notion of a record, a datatype that aggregates a fixed set of labelled objects, possibly of different types, into a single object. It is so called because of the struct keyword used in declaring them, which is short for structure or, more precisely, user-defined data structure.

A struct declaration consists of a list of fields, each of which can have any type. The total storage required for a struct object is the sum of the storage requirements of all the fields, plus any internal padding.

For example:

struct account {
    int account_number;
    char *first_name;
    char *last_name;
    float balance;
 };
 

defines a type, referred to as struct account. To create a new variable of this type, we can write

struct account s;
 

which has an integer component, accessed by s.account_number, and a floating-point component, accessed by s.balance, as well as the first_name and last_name components. The structure s contains all four values, and all four fields may be changed independently.

The primary use of a struct is for the construction of complex datatypes, but in practice they are sometimes used to circumvent standard C conventions to create a kind of primitive subtyping. For example, common Internet protocols rely on the fact that C compilers insert padding between struct fields in predictable ways; thus the code

struct ifoo_version_42 {
    long x, y, z;
    char *name;
    long a, b, c;
 };
 struct ifoo_old_stub {
    long x, y;
 };
 void operate_on_ifoo(struct ifoo_version_42 *);
 struct ifoo_old_stub s;
 . . .
 operate_on_ifoo(&s);
 

is often assumed to work as expected, if the operate_on_ifoo function only accesses fields x and y of its argument.

Since writing struct account repeatedly in code becomes cumbersome, it is not unusual to see a typedef statement to provide a more convenient type synonym for the struct. For example:

typedef struct account_ {
    int    account_number;
    char   *first_name;
    char   *last_name;
    float  balance;
 } account;
 

In C++ the only difference between a struct and a class is the default access level, which is private for classes and public for structs.

Note that while classes and the "class" keyword were completely new in C++, the C programming language already had a crude type of structs. For all intents and purposes, C++ structs form a superset of C structs: virtually all valid C structs are valid C++ structs with the same semantics.

Aggregation

Aggregation differs from composition in that it does not induce ownership. That is, in composition, when the containing object is destroyed, so are the contained objects. In aggregation, this is not necessarily true. For example, a university consists of various departments (e.g., chemistry), and each department contains a number of professors. If the university closes, the departments will no longer exist, but the professors in those departments will. Therefore, a University can be seen as a composition of departments, whereas departments have an aggregation of professors.

Composition is usually implemented such that an object contains another object. For example, in C++:

 class Department;
 
 class University
 {
   ...
   private:
   Professor faculty[20];
   ...
 };
 

In aggregation, the object may only contain a reference or pointer to the object:

 class Professor;
 
 class Department
 {
   ...
   private:
   Professor* members[5];
   ...
 };
 

Sometimes aggregation is also referred to simply as composition.

See also

See also: Object composition, Algol, Binary tree, COBOL, C Plus Plus, C plus plus, C programming language, Chemistry, Class (computer science), Computer science