In computer science, object composition (not to be confused with function composition) is a way to combine simple objects or data types into more complex ones. Compositions are a critical building block of many basic data structures, including the tagged union, the linked list, and the binary tree, as well as the object used in object-oriented programming.
Composited (composed) objects are often referred to as having a "has a" relationship. A real-world example of composition may be seen in an automobile: the objects wheel, steering wheel, seat, gearbox and engine may have no functionality by themselves, but an object called automobile containing all of those objects would serve a higher function, greater than the sum of its parts.
When, in a language, objects are typed, types can often be divided into composite and noncomposite types, and composition can be regarded as a relationship between types: an object of a composite type (e.g. car) "has an" object of a simpler type (e.g. wheel).
Composition must be distinguished from subtyping, which is the process of adding detail to a general data type to create a more specific data type. For instance, cars may be a specific type of vehicle: car is a vehicle. Subtyping doesn't describe a relationship between different objects, but instead, says that objects of a type are simultaneously objects of another type.
In programming languages, composite objects are usually expressed by means of references from one object to another; depending on the language, such references may be known as fields, members, properties or attributes, and the resulting composition as a structure, storage record, tuple, user-defined type (UDT), or composite type. Fields are given a unique name so that each one can be distinguished from the others. However, having such references doesn't necessarily mean that an object is a composite. It is only called composite if the objects it refers to are really its parts, i.e. have no independent existence. For details, see the aggregation section below.
Contents |
In UML, composition is depicted as a filled diamond and a solid line. It always implies a multiplicity of 1 or 0..1, as no more than one object at a time can have lifetime responsibility for another object.
The more general form, aggregation, is depicted as an unfilled diamond and a solid line. The image below shows both composition and aggregation. The C++ code below shows what the source code is likely to look like.
// Composition class Automobile { private: Carburetor* carb; public: Automobile() : carb(new Carburetor()) { } virtual ~Automobile() { delete carb; } };
// Aggregation class Pond { private: std::vector<Duck*> ducks; };
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 Organism
, and it could inherit some attributes from Organism
(every organism has an age), while extending the definition of Organism
with new attributes (not every organism has a gender, but every person does).
Objects can be composited recursively with 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 have references to others of the same type. In C, for example, a binary tree can be defined like:
struct bintree { struct bintree *left, *right; // some data };
If pointers left
and right
are valid, the node is thought to be a branch referring 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.
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 68 got it from COBOL and Pascal got it, more or less indirectly, from ALGOL 68. Common Lisp provides structures and classes (the latter via the Common Lisp Object System).
01 customer-record. 03 customer-number pic 9(8) comp. 03 customer-name. 05 given-names pic x(15). 05 initial-2 pic x. 05 surname pic x(15). 03 customer-address. 05 street. 07 house-number pic 999 comp. 07 street-name pic x(15). 05 city pic x(10). 05 country-code pic x(3). 05 postcode pic x(8). 03 amount-owing pic 9(8) comp.
Arrays were the only composite data type in Algol 60.
GeSHi Error: GeSHi could not find the language pli (using path /usr/share/php-geshi/geshi/) (code 2)
You need to specify a language like this: <source lang="html4strict">...</source>
Supported languages for syntax highlighting:
abap, actionscript, actionscript3, ada, apache, applescript, apt_sources, asm, asp, autoit, avisynth, bash, basic4gl, bf, bibtex, blitzbasic, bnf, boo, c, c_mac, caddcl, cadlisp, cfdg, cfm, cil, cmake, cobol, cpp, cpp-qt, csharp, css, d, dcs, delphi, diff, div, dos, dot, eiffel, email, erlang, fo, fortran, freebasic, genero, gettext, glsl, gml, gnuplot, groovy, haskell, hq9plus, html4strict, idl, ini, inno, intercal, io, java, java5, javascript, kixtart, klonec, klonecpp, latex, lisp, locobasic, lolcode, lotusformulas, lotusscript, lscript, lsl2, lua, m68k, make, matlab, mirc, modula3, mpasm, mxml, mysql, nsis, oberon2, objc, ocaml, ocaml-brief, oobas, oracle11, oracle8, pascal, per, perl, php, php-brief, pic16, pixelbender, plsql, povray, powershell, progress, prolog, properties, providex, python, qbasic, rails, rebol, reg, robots, ruby, sas, scala, scheme, scilab, sdlbasic, smalltalk, smarty, sql, tcl, teraterm, text, thinbasic, tsql, typoscript, vb, vbnet, verilog, vhdl, vim, visualfoxpro, visualprolog, whitespace, whois, winbatch, xml, xorg_conf, xpp, z80
GeSHi Error: GeSHi could not find the language algol68 (using path /usr/share/php-geshi/geshi/) (code 2)
You need to specify a language like this: <source lang="html4strict">...</source>
Supported languages for syntax highlighting:
abap, actionscript, actionscript3, ada, apache, applescript, apt_sources, asm, asp, autoit, avisynth, bash, basic4gl, bf, bibtex, blitzbasic, bnf, boo, c, c_mac, caddcl, cadlisp, cfdg, cfm, cil, cmake, cobol, cpp, cpp-qt, csharp, css, d, dcs, delphi, diff, div, dos, dot, eiffel, email, erlang, fo, fortran, freebasic, genero, gettext, glsl, gml, gnuplot, groovy, haskell, hq9plus, html4strict, idl, ini, inno, intercal, io, java, java5, javascript, kixtart, klonec, klonecpp, latex, lisp, locobasic, lolcode, lotusformulas, lotusscript, lscript, lsl2, lua, m68k, make, matlab, mirc, modula3, mpasm, mxml, mysql, nsis, oberon2, objc, ocaml, ocaml-brief, oobas, oracle11, oracle8, pascal, per, perl, php, php-brief, pic16, pixelbender, plsql, povray, powershell, progress, prolog, properties, providex, python, qbasic, rails, rebol, reg, robots, ruby, sas, scala, scheme, scilab, sdlbasic, smalltalk, smarty, sql, tcl, teraterm, text, thinbasic, tsql, typoscript, vb, vbnet, verilog, vhdl, vim, visualfoxpro, visualprolog, whitespace, whois, winbatch, xml, xorg_conf, xpp, z80
For an example of all this, here is the traditional linked list declaration:
GeSHi Error: GeSHi could not find the language algol68 (using path /usr/share/php-geshi/geshi/) (code 2)
You need to specify a language like this: <source lang="html4strict">...</source>
Supported languages for syntax highlighting:
abap, actionscript, actionscript3, ada, apache, applescript, apt_sources, asm, asp, autoit, avisynth, bash, basic4gl, bf, bibtex, blitzbasic, bnf, boo, c, c_mac, caddcl, cadlisp, cfdg, cfm, cil, cmake, cobol, cpp, cpp-qt, csharp, css, d, dcs, delphi, diff, div, dos, dot, eiffel, email, erlang, fo, fortran, freebasic, genero, gettext, glsl, gml, gnuplot, groovy, haskell, hq9plus, html4strict, idl, ini, inno, intercal, io, java, java5, javascript, kixtart, klonec, klonecpp, latex, lisp, locobasic, lolcode, lotusformulas, lotusscript, lscript, lsl2, lua, m68k, make, matlab, mirc, modula3, mpasm, mxml, mysql, nsis, oberon2, objc, ocaml, ocaml-brief, oobas, oracle11, oracle8, pascal, per, perl, php, php-brief, pic16, pixelbender, plsql, povray, powershell, progress, prolog, properties, providex, python, qbasic, rails, rebol, reg, robots, ruby, sas, scala, scheme, scilab, sdlbasic, smalltalk, smarty, sql, tcl, teraterm, text, thinbasic, tsql, typoscript, vb, vbnet, verilog, vhdl, vim, visualfoxpro, visualprolog, whitespace, whois, winbatch, xml, xorg_conf, xpp, z80
Note that for ALGOL 68 only the newtypet name appears to the left of the equality, and most notably the construction is made – and can be read – from left to right without regard to priorities.
type a = array [1..10] of integer; b = record a, b, c: real; i, j, k: integer; end;
# define max 99 struct newtypet { double a, b, c; float r; short i, j, k; } newarrayt[10] [max + 1];
Fortran 77 has arrays, but lacked any formal record/structure definitions. Typically compound structures were built up using EQUIVALENCE or COMMON statements:
CHARACTER NAME*32, ADDR*32, PHONE*16 REAL OWING COMMON /CUST/NAME, ADDR, PHONE, OWING
type Cust is record Name : Name_Type; Addr : Addr_Type; Phone : Phone_Type; Owing : Integer range 1..999999; end record;
const int max = 99; class{ public: double a, b, c; float &r; short i, j, k; }newtypet[10] [max + 1];
max = 99 class NewTypeT: def __init__(self): self.a = self.b = self.c = 0 self.i = self.j = self.k = 0.0 class R: def __init__(self): self.r = None self.r = R() # Initialise an example array of this class. newarrayt = [[NewTypeT() for i in range(max + 1)] for j in range(10)]
Arrays and strings were inherited from FORTRAN 77, and a new reserved word was introduced: type
type newtypet double precision a, b, c integer*2 i, j, k * No pointer type REF REAL R end type type (newtypet) t(10, 100)
FORTRAN 90 updated and included FORTRAN IV's concept called NAMELIST.
INTEGER :: jan = 1, feb = 2, mar = 3, apr = 4 NAMELIST / week / jan, feb, mar, apr
Common Lisp provides structures and the ANSI Common Lisp standard added CLOS classes.
(defclass some-class () ((f :type float) (i :type integer) (a :type (array integer (10)))))
For more details about composition in C/C++, see Composite type.
Aggregation differs from ordinary composition in that it does not imply ownership. In composition, when the owning object is destroyed, so are the contained objects. In aggregation, this is not necessarily true. For example, a university owns various departments (e.g., chemistry), and each department has a number of professors. If the university closes, the departments will no longer exist, but the professors in those departments will continue to exist. Therefore, a University can be seen as a composition of departments, whereas departments have an aggregation of professors. In addition, a Professor could work in more than one department, but a department could not be part of more than one university.
Composition is usually implemented such that an object contains another object. For example, in C++:
class Professor; class Department { ... private: // Aggregation Professor* members[5]; ... }; class University { ... private: Department faculty[20]; ... create dept() { ... // Composition faculty[0] = Department(...); faculty[1] = Department(...); ... } };
In aggregation, the object may only contain a reference or pointer to the object (and not have lifetime responsibility for it):
Sometimes aggregation is referred to as composition when the distinction between ordinary composition and aggregation is unimportant.
The above code would transform into the following UML Class diagram:
Composition that is used to store several instances of the composited data type is referred to as containment. Examples of such containers are arrays, linked lists, binary trees and associative arrays.
In UML, containment is depicted with a multiplicity of 1 or 0..n (depending on the issue of ownership), indicating that the data type is composed of an unknown number of instances of the composited data type.
In Microsoft's Component Object Model aggregation means that an object exports, as if it were their owner, one or several interfaces of another object it owns. Formally, this is more similar to composition or encapsulation than aggregation. However, instead of implementing the exported interfaces by calling the interfaces of the owned object, the interfaces of the owned object themselves are exported. The owned object is responsible for assuring that methods of those interfaces inherited from IUnknown actually invoke the corresponding methods of the owner. This is to guarantee that the reference count of the owner is correct and all interfaces of the owner are accessible through the exported interface, while no other (private) interfaces of the owned object are accessible.[1]
General References: