Object composition

Last updated

In computer science, object composition and object aggregation are closely related ways to combine objects or data types into more complex ones. In conversation the distinction between composition and aggregation is often ignored. [1] Common kinds of compositions are objects used in object-oriented programming, tagged unions, sets, sequences, and various graph structures. Object compositions relate to, but are not the same as, data structures.

Contents

Object composition refers to the logical or conceptual structure of the information, not the implementation or physical data structure used to represent it[ citation needed ]. For example, a sequence differs from a set because (among other things) the order of the composed items matters for the former but not the latter. Data structures such as arrays, linked lists, hash tables, and many others can be used to implement either of them. Perhaps confusingly, some of the same terms are used for both data structures and composites. For example, "binary tree" can refer to either: as a data structure it is a means of accessing a linear sequence of items, and the actual positions of items in the tree are irrelevant (the tree can be internally rearranged however one likes, without changing its meaning). However, as an object composition, the positions are relevant, and changing them would change the meaning (as for example in cladograms)[ citation needed ].

Programming technique

Object-oriented programming is based on objects to encapsulate data and behavior. It uses two main techniques for assembling and composing functionality into more complex ones, sub-typing and object composition. [2] Object composition is about combining objects within compound objects, and at the same time, ensuring the encapsulation of each object by using their well-defined interface without visibility of their internals. In this regard, object composition differs from data structures, which do not enforce encapsulation.

Object composition may also be about a group of multiple related objects, such as a set or a sequence of objects. Delegation may enrich composition by forwarding requests or calls made to the enclosing composite object to one of its internal components. [3]

In class-based and typed programming languages, types can be divided into composite and non-composite types, and composition can be regarded as a relationship between types: an object of a composite type (e.g. car) "has" objects of other types (e.g. wheel). When a composite object contains several sub-objects of the same type, they may be assigned to particular roles, often distinguished by names or numbers. For example, a Point object might contain 3 numbers, each representing distance along a different axis, such as 'x', 'y', and 'z'. The study of part-whole relationships in general, is mereology.

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. The study of such relationships is ontology.

In prototype-based programming languages such as JavaScript, objects can dynamically inherit the behaviors from a prototype object at the moment of their instantiation. Composition must be distinguished from prototyping: the newly instantiated object inherits the composition of its prototype, but it may itself be composed on its own.

Composite objects may be represented in storage by co-locating the composed objects, by co-locating references, or in many other ways. The items within a composite object may be referred to as attributes, fields , members, properties, or other names, and the resulting composition as composite type , storage record , structure, tuple , or a user-defined type (UDT). For details, see the aggregation section below.

UML modeling technique

Object composition using UML properties to compose objects UML properties of a bicycle.png
Object composition using UML properties to compose objects

In UML modeling, objects can be conceptually composed, independently of the implementation with a programming language. There are four ways of composing objects in UML: property, association, aggregation and composition: [4]

The relationship between the aggregate and its components is a weak "has-a" relationship: The components may be part of several aggregates, may be accessed through other objects without going through the aggregate, and may outlive the aggregate object. [4] The state of the component object still forms part of the aggregate object.[ citation needed ]

The relationship between the composite and its parts is a strong “has-a” relationship: The composite object has sole "responsibility for the existence and storage of the composed objects", the composed object can be part of at most one composite, and "If a composite object is deleted, all of its part instances that are objects are deleted with it". Thus in UML, composition has a more narrow meaning than the usual object composition.

UML notation for association, composition and aggregation UML association, aggregation and composition examples for a bicycle.png
UML notation for association, composition and aggregation

The graphical notation represents:

Aggregation

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++:

classProfessor;// Defined elsewhereclassDepartment{public:Department(conststd::string&title):title_(title){}private:// Aggregation: |Professors| may outlive the |Department|.std::vector<std::weak_ptr<Professor>>members_;conststd::stringtitle_;};classUniversity{public:University()=default;private:// Composition: |Department|s exist only as long as the faculty exists.std::vector<Department>faculty_={Department("chemistry"),Department("physics"),Department("arts"),};};

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:

Aggregation-Composition3.png

Aggregation in COM

Aggregation in COM Simple COM aggregation diagram.svg
Aggregation in COM

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. [5]

Special forms

Containment

Composition that is used to store several instances of the composited data type is referred to as containment. Examples of such containers are arrays, associative arrays, binary trees, and linked lists.

In UML, containment is depicted with a multiplicity of 0..* or 1..*, indicating that the composite object is composed of an unknown number of instances of the composed class.

Recursive composition

Objects can be composed recursively, and their type is then called recursive type. Examples includes various kinds of trees, DAGs, and graphs. 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.

In UML, recursive composition is depicted with an association, aggregation or composition of a class with itself.

Composite pattern

The composite design pattern is an object-oriented design based on composite types, that combines recursive composition and containment to implement complex part-whole hierarchies.

Composite types in C

This is an example of composition in C.

structPerson{intage;charname[20];enum{job_seeking,professional,non_professional,retired,student}employment;};

In this example, the primitive (noncomposite) types int, enum {job_seeking, professional, non_professional, retired, student} and the composite array type char[] are combined to form the composite structure Person. Each Person structure then "has an" age, name, and an employment type.

Timeline of 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 widespread programming language to support records directly; [6] 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).[ citation needed ]

1959 – COBOL
01  customer-record.03  customer-numberpic 9(8)comp.03  customer-name.05  given-namespic x(15).05  initial-2pic x.05  surnamepic x(15).03  customer-address.05  street.07  street-namepic x(15).09  house-numberpic 999comp.05  citypic x(10).05  country-codepic x(3).05  postcodepic x(8).03  amount-owingpic 9(8)comp.
1960 – ALGOL 60

Arrays were the only composite data type in Algol 60.

1964 – PL/I
dcl 1 newtypet based (P);  2 (a, b, c) fixed bin(31),  2 (i, j, k) float,  2 r ptr; allocate newtypet; 
1968 – ALGOL 68
int max = 99; mode newtypet = [0..9] [0..max]struct (  long real a, b, c, short int i, j, k, ref real r ); newtypet newarrayt = (1, 2, 3, 4, 5, 6, heap real := 7) 

For example, a linked list might be declared as:

mode node = union (real, int, compl, string),  list = struct (node val, ref list next); 

For ALGOL 68 only the type 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.

1970 – Pascal
typea=array[1..10]ofinteger;b=recorda,b,c:real;i,j,k:integer;end;
1972 – K&R C
#define max 99structnewtypet{doublea,b,c;floatr;shorti,j,k;}newarrayt[10][max+1];
1977 – FORTRAN 77

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*16REAL OWINGCOMMON/CUST/NAME,ADDR,PHONE,OWING
1983 – Ada
typeCustisrecordName:Name_Type;Addr:Addr_Type;Phone:Phone_Type;Owing:Integerrange1..999999;end record;

Ada 95 brought OOP concepts through tagged types (the equivalent of a C++ class), Ada 2012 added support for substitution verification through class-wide contracts.

1983 – C++
constintmax=99;class{public:doublea,b,c;float&r;shorti,j,k;}newtypet[10][max+1];
1991 – Python
max=99classNewTypeT:def__init__(self):self.a=self.b=self.c=0self.i=self.j=self.k=0.0# Initialise an example array of this class.newarrayt=[[NewTypeT()foriinrange(max+1)]forjinrange(10)]
1992 – FORTRAN 90

Arrays and strings were inherited from FORTRAN 77, and a new reserved word was introduced: type

type newtypetdouble precision a,b,cinteger*2i,j,k*Nopointer type REFREAL Rend typetype(newtypet)t(10,100)

FORTRAN 90 updated and included FORTRAN IV's concept called NAMELIST.

INTEGER::jan=1,feb=2,mar=3,apr=4NAMELIST/week/jan,feb,mar,apr
1994 – ANSI Common Lisp

Common Lisp provides structures and the ANSI Common Lisp standard added CLOS classes.

(defclasssome-class()((f:typefloat)(i:typeinteger)(a:type(arrayinteger(10)))))

For more details about composition in C/C++, see Composite type.

See also

Related Research Articles

In software engineering, the composite pattern is a partitioning design pattern. The composite pattern describes a group of objects that are treated the same way as a single instance of the same type of object. The intent of a composite is to "compose" objects into tree structures to represent part-whole hierarchies. Implementing the composite pattern lets clients treat individual objects and compositions uniformly.

In object-oriented programming, the iterator pattern is a design pattern in which an iterator is used to traverse a container and access the container's elements. The iterator pattern decouples algorithms from containers; in some cases, algorithms are necessarily container-specific and thus cannot be decoupled.

In computer programming, an iterator is an object that enables a programmer to traverse a container, particularly lists. Various types of iterators are often provided via a container's interface. Though the interface and semantics of a given iterator are fixed, iterators are often implemented in terms of the structures underlying a container implementation and are often tightly coupled to the container to enable the operational semantics of the iterator. An iterator performs traversal and also gives access to data elements in a container, but does not itself perform iteration.

In computer science, imperative programming is a programming paradigm of software that uses statements that change a program's state. In much the same way that the imperative mood in natural languages expresses commands, an imperative program consists of commands for the computer to perform. Imperative programming focuses on describing how a program operates step by step, rather than on high-level descriptions of its expected results.

In computer science, a composite data type or compound data type is any data type which can be constructed in a program using the programming language's primitive data types and other composite types. It is sometimes called a structure or aggregate data type, although the latter term may also refer to arrays, lists, etc. The act of constructing a composite type is known as composition. Composite data types are often contrasted with scalar variables.

<span class="mw-page-title-main">Pointer (computer programming)</span> Object which stores memory addresses in a computer program

In computer science, a pointer is an object in many programming languages that stores a memory address. This can be that of another value located in computer memory, or in some cases, that of memory-mapped computer hardware. A pointer references a location in memory, and obtaining the value stored at that location is known as dereferencing the pointer. As an analogy, a page number in a book's index could be considered a pointer to the corresponding page; dereferencing such a pointer would be done by flipping to the page with the given page number and reading the text found on that page. The actual format and content of a pointer variable is dependent on the underlying computer architecture.

In computer science, a union is a value that may have any of several representations or formats within the same position in memory; that consists of a variable that may hold such a data structure. Some programming languages support special data types, called union types, to describe such values and variables. In other words, a union type definition will specify which of a number of permitted primitive types may be stored in its instances, e.g., "float or long integer". In contrast with a record, which could be defined to contain both a float and an integer; in a union, there is only one value at any given time.

In computer science, a record is a basic data structure. Records in a database or spreadsheet are usually called "rows".

In computer programming, a function object is a construct allowing an object to be invoked or called as if it were an ordinary function, usually with the same syntax. Function objects are often called functors.

In computer science, type safety and type soundness are the extent to which a programming language discourages or prevents type errors. Type safety is sometimes alternatively considered to be a property of facilities of a computer language; that is, some facilities are type-safe and their usage will not result in type errors, while other facilities in the same language may be type-unsafe and a program using them may encounter type errors. The behaviors classified as type errors by a given programming language are usually those that result from attempts to perform operations on values that are not of the appropriate data type, e.g., adding a string to an integer when there's no definition on how to handle this case. This classification is partly based on opinion.

A struct in the C programming language is a composite data type declaration that defines a physically grouped list of variables under one name in a block of memory, allowing the different variables to be accessed via a single pointer or by the struct declared name which returns the same address. The struct data type can contain other data types so is used for mixed-data-type records such as a hard-drive directory entry, or other mixed-type records.

<span class="mw-page-title-main">Class diagram</span> Type of static structure diagram

In software engineering, a class diagram in the Unified Modeling Language (UML) is a type of static structure diagram that describes the structure of a system by showing the system's classes, their attributes, operations, and the relationships among objects.

Glossary of Unified Modeling Language (UML) terms provides a compilation of terminology used in all versions of UML, along with their definitions. Any notable distinctions that may exist between versions are noted with the individual entry it applies to.

A class in C++ is a user-defined type or data structure declared with keyword class that has data and functions as its members whose access is governed by the three access specifiers private, protected or public. By default access to members of a C++ class is private. The private members are not accessible outside the class; they can be accessed only through methods of the class. The public members form an interface to the class and are accessible outside the class.

A foreign function interface (FFI) is a mechanism by which a program written in one programming language can call routines or make use of services written or compiled in another one. An FFI is often used in contexts where calls are made into binary dynamic-link library.

sizeof is a unary operator in the programming languages C and C++. It generates the storage size of an expression or a data type, measured in the number of char-sized units. Consequently, the construct sizeof (char) is guaranteed to be 1. The actual number of bits of type char is specified by the preprocessor macro CHAR_BIT, defined in the standard include file limits.h. On most modern computing platforms this is eight bits. The result of sizeof has an unsigned integer type that is usually denoted by size_t.

In computer science, a type punning is any programming technique that subverts or circumvents the type system of a programming language in order to achieve an effect that would be difficult or impossible to achieve within the bounds of the formal language.

C++ doesn't have:

In computer programming, a variable-length array (VLA), also called variable-sized or runtime-sized, is an array data structure whose length is determined at run time . In C, the VLA is said to have a variably modified type that depends on a value.

This article compares a large number of programming languages by tabulating their data types, their expression, statement, and declaration syntax, and some common operating-system interfaces.

References

  1. Yaiser, Michelle. "Object-oriented programming concepts: Composition and aggregation". Archived from the original on April 8, 2015. There is a closely related concept to composition called aggregation. In conversation the differences between composition and aggregation are often ignored.
  2. Design patterns : elements of reusable object-oriented software. Gamma, Erich., Helm, Richard (Computer scientist), Johnson, Ralph E., 1955-, Vlissides, John. Reading, Mass.: Addison-Wesley. 1995. ISBN   0-201-63361-2. OCLC   31171684.{{cite book}}: CS1 maint: others (link)
  3. Ostermann, Klaus; Mezini, Mira (October 1, 2001). "Object-oriented composition untangled". ACM SIGPLAN Notices. 36 (11): 283–299. doi:10.1145/504311.504303. ISSN   0362-1340.
  4. 1 2 OMG (2017). "Unified Modeling Language Specification Version 2.5.1". www.omg.org. p. 109-110,197-201. Retrieved October 4, 2020.
  5. "Aggregation". Platform SDK for Windows XP SP2. Microsoft. Retrieved November 4, 2007.
  6. Sebesta, Robert W. Concepts of Programming Languages (Third ed.). Addison-Wesley Publishing Company, Inc. p.  218. ISBN   0-8053-7133-8.