Delegation (object-oriented programming)

Last updated

In object-oriented programming, delegation refers to evaluating a member (property or method) of one object (the receiver) in the context of another original object (the sender). Delegation can be done explicitly, by passing the sending object to the receiving object, which can be done in any object-oriented language; or implicitly, by the member lookup rules of the language, which requires language support for the feature. Implicit delegation is the fundamental method for behavior reuse in prototype-based programming, corresponding to inheritance in class-based programming. The best-known languages that support delegation at the language level are Self, which incorporates the notion of delegation through its notion of mutable parent slots that are used upon method lookup on self calls, and JavaScript; see JavaScript delegation.

Contents

The term delegation is also used loosely for various other relationships between objects; see delegation (programming) for more. Frequently confused concepts are simply using another object, more precisely referred to as consultation or aggregation ; and evaluating a member on one object by evaluating the corresponding member on another object, notably in the context of the receiving object, which is more precisely referred to as forwarding (when a wrapper object doesn't pass itself to the wrapped object). [1] [2] [lower-alpha 1] The delegation pattern is a software design pattern for implementing delegation, though this term is also used loosely for consultation or forwarding.

Overview

This sense of delegation as programming language feature making use of the method lookup rules for dispatching so-called self-calls was defined by Lieberman in his 1986 paper "Using Prototypical Objects to Implement Shared Behavior in Object-Oriented Systems".

Delegation is dependent upon dynamic binding, as it requires that a given method call can invoke different segments of code at runtime[ citation needed ]. It is used throughout macOS (and its predecessor NeXTStep) as a means of customizing the behavior of program components. [3] It enables implementations such as making use of a single OS-provided class to manage windows, because the class takes a delegate that is program-specific and can override default behavior as needed. For instance, when the user clicks the close box, the window manager sends the delegate a windowShouldClose: call, and the delegate can delay the closing of the window, if there is unsaved data represented by the window's contents.

Delegation can be characterized (and distinguished from forwarding) as late binding of self: [4]

... messages sent to the self (or this) variable in the parent will "come back" to the object that originally received the message.

That is, the self in a method definition in the receiving object is not statically bound to that object at definition time (such as compile time or when the function is attached to an object), but rather at evaluation time, it is bound to the original object.

It has been argued that delegation may in some cases be preferred to inheritance to make program code more readable and understandable. [5] Despite explicit delegation being fairly widespread, relatively few major programming languages implement delegation as an alternative model to inheritance. The precise relationship between delegation and inheritance is complicated; some authors consider them equivalent, or one a special case of the other. [6]

Language support for delegation

In languages that support delegation via method lookup rules, method dispatching is defined the way it is defined for virtual methods in inheritance: It is always the most specific method that is chosen during method lookup. Hence it is the original receiver entity that is the start of method lookup even though it has passed on control to some other object (through a delegation link, not an object reference).

Delegation has the advantage that it can take place at run time and affect only a subset of entities of some type and can even be removed at run time. Inheritance, by contrast, typically targets the type rather than the instances, and is restricted to compile time. On the other hand, inheritance can be statically type-checked, while delegation generally cannot without generics (although a restricted version of delegation can be statically typesafe [7] ). Delegation can be termed "run-time inheritance for specific objects."

Here is a pseudocode example in a C#/Java like language:

classA{voidfoo(){// "this" also known under the names "current", "me" and "self" in other languagesthis.bar();}voidbar(){print("a.bar");}}classB{privatedelegateAa;// delegation linkpublicB(Aa){this.a=a;}voidfoo(){a.foo();// call foo() on the a-instance}voidbar(){print("b.bar");}}a=newA();b=newB(a);// establish delegation between two objects

Calling b.foo() will result in b.bar being printed, since this refers to the original receiver object, b, within the context of a. The resulting ambiguity of this is referred to as object schizophrenia.

Translating the implicit this into an explicit parameter, the call (in B, with a a delegate) a.foo() translates to A.foo(b), using the type of a for method resolution, but the delegating object b for the this argument.

Using inheritance, the analogous code (using capital letters to emphasize that resolution is based on classes, not objects) is:

classA{voidfoo(){this.bar();}voidbar(){print("A.bar");}}classBextendsA{publicB(){}voidfoo(){super.foo();// call foo() of the superclass (A)}voidbar(){print("B.bar");}}b=newB();

Calling b.foo() will result in B.bar. In this case, this is unambiguous: there is a single object, b, and this.bar() resolves to the method on the subclass.

Programming languages in general do not support this unusual form of delegation as a language concept, but there are a few exceptions[ citation needed ].

Dual inheritance

If the language supports both delegation and inheritance one can do dual inheritance by utilizing both mechanisms at the same time as in

classCextendsA{delegationlinkDd;}

This calls for additional rules for method lookup, as there are now potentially two methods that can be denoted as the most specific (due to the two lookup paths).

Delegation can be described as a low level mechanism for sharing code and data between entities. Thus it builds the foundation for other language constructs. Notably role-oriented programming languages have been utilizing delegation, but especially the older ones factually used aggregation while claiming to use delegation. This should not be considered cheating, merely the plural definitions of what delegation means (as described above).

More recently work has also been done on distributing delegation, so e.g. clients of a search engine (finding cheap hotel rooms) can use a shared entity using delegation to share best hits and general re-usable functionality.

Delegation has also been suggested for advice resolution in aspect-oriented programming by Ernst and Lorenz in 2003.

See also

Distinguish:

Notes

  1. Beck 1997 uses the terms "simple delegation" for when the receiving object does not have access to the sending object, and "self delegation" for when the receiving object does have access to the sending object; in modern language these are "forwarding" and "delegation", as used in this article.

Related Research Articles

A visitor pattern is a software design pattern and separates the algorithm from the object structure. Because of this separation new operations can be added to existing object structures without modifying the structures. It is one way to follow the open/closed principle in object-oriented programming and software engineering.

<i>Design Patterns</i> 1994 software engineering book

Design Patterns: Elements of Reusable Object-Oriented Software (1994) is a software engineering book describing software design patterns. The book was written by Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides, with a foreword by Grady Booch. The book is divided into two parts, with the first two chapters exploring the capabilities and pitfalls of object-oriented programming, and the remaining chapters describing 23 classic software design patterns. The book includes examples in C++ and Smalltalk.

Prototype-based programming is a style of object-oriented programming in which behaviour reuse is performed via a process of reusing existing objects that serve as prototypes. This model can also be known as prototypal, prototype-oriented,classless, or instance-based programming.

In programming languages, a closure, also lexical closure or function closure, is a technique for implementing lexically scoped name binding in a language with first-class functions. Operationally, a closure is a record storing a function together with an environment. The environment is a mapping associating each free variable of the function with the value or reference to which the name was bound when the closure was created. Unlike a plain function, a closure allows the function to access those captured variables through the closure's copies of their values or references, even when the function is invoked outside their scope.

In software engineering, the delegation pattern is an object-oriented design pattern that allows object composition to achieve the same code reuse as inheritance.

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 decorator pattern is a design pattern that allows behavior to be added to an individual object, dynamically, without affecting the behavior of other objects from the same class. The decorator pattern is often useful for adhering to the Single Responsibility Principle, as it allows functionality to be divided between classes with unique areas of concern as well as to the Open-Closed Principle, by allowing the functionality of a class to be extended without being modified. Decorator use can be more efficient than subclassing, because an object's behavior can be augmented without defining an entirely new object.

In computer programming, the strategy pattern is a behavioral software design pattern that enables selecting an algorithm at runtime. Instead of implementing a single algorithm directly, code receives run-time instructions as to which in a family of algorithms to use.

In software systems, encapsulation refers to the bundling of data with the mechanisms or methods that operate on the data. It may also refer to the limiting of direct access to some of that data, such as an object's components. Encapsulation allows developers to present a consistent and usable interface which is independent of how a system is implemented internally. As one example, encapsulation can be used to hide the values or state of a structured data object inside a class, preventing direct access to them by clients in a way that could expose hidden implementation details or violate state invariance maintained by the methods.

In object-oriented programming languages, a mixin is a class that contains methods for use by other classes without having to be the parent class of those other classes. How those other classes gain access to the mixin's methods depends on the language. Mixins are sometimes described as being "included" rather than "inherited".

In computer science, reflective programming or reflection is the ability of a process to examine, introspect, and modify its own structure and behavior.

In object-oriented programming, in languages such as C++, and Object Pascal, a virtual function or virtual method is an inheritable and overridable function or method for which dynamic dispatch is facilitated. This concept is an important part of the (runtime) polymorphism portion of object-oriented programming (OOP). In short, a virtual function defines a target function to be executed, but the target might not be known at compile time.

In object-oriented programming, inheritance is the mechanism of basing an object or class upon another object or class, retaining similar implementation. Also defined as deriving new classes from existing ones such as super class or base class and then forming them into a hierarchy of classes. In most class-based object-oriented languages, an object created through inheritance, a "child object", acquires all the properties and behaviors of the "parent object", with the exception of: constructors, destructors, overloaded operators and friend functions of the base class. Inheritance allows programmers to create classes that are built upon existing classes, to specify a new implementation while maintaining the same behaviors, to reuse code and to independently extend original software via public classes and interfaces. The relationships of objects or classes through inheritance give rise to a directed acyclic graph.

In computer programming, a trait is a concept used in programming languages which represents a set of methods that can be used to extend the functionality of a class.

this, self, and Me are keywords used in some computer programming languages to refer to the object, class, or other entity of which the currently running code is a part. The entity referred to by these keywords thus depends on the execution context. Different programming languages use these keywords in slightly different ways. In languages where a keyword like "this" is mandatory, the keyword is the only way to access data and methods stored in the current object. Where optional, they can disambiguate variables and functions with the same name.

<span class="mw-page-title-main">Composition over inheritance</span> Software design pattern

Composition over inheritance in object-oriented programming (OOP) is the principle that classes should achieve polymorphic behavior and code reuse by their composition rather than inheritance from a base or parent class. This principle of OOP is discussed in the book Design Patterns (1994).

Object-Oriented Programming (OOP) is a programming paradigm based on the concept of "objects", which can contain data and code. The data is in the form of fields, and the code is in the form of procedures.

Object schizophrenia or self schizophrenia is a complication arising from delegation and related techniques in object-oriented programming, where self/this can refer to more than one object. By way of metaphor with the public confusion of dissociative identity disorder with the psychiatric diagnosis of schizophrenia, the former being associated with "split personalities," this configuration is called object schizophrenia or self schizophrenia in object-oriented programming.

Objective-C is a high-level general-purpose, object-oriented programming language that adds Smalltalk-style messaging to the C programming language. Originally developed by Brad Cox and Tom Love in the early 1980s, it was selected by NeXT for its NeXTSTEP operating system. Due to Apple macOS’s direct lineage from NeXTSTEP, Objective-C was the standard programming language used, supported, and promoted by Apple for developing macOS and iOS applications until the introduction of the Swift programming language in 2014.

In object-oriented programming, forwarding means that using a member of an object results in actually using the corresponding member of a different object: the use is forwarded to another object. Forwarding is used in a number of design patterns, where some members are forwarded to another object, while others are handled by the directly used object. The forwarding object is frequently called a wrapper object, and explicit forwarding members are called wrapper functions.

References

  1. Gamma et al. 1995, "Delegation", pp. 20–21.
  2. Beck 1997, "Delegation", pp. 64–69.
  3. Apple (2009-08-20). "Cocoa Fundamentals Guide: Delegates and Data Sources". Apple Developer Connection. Retrieved 2009-09-11.
  4. "Intersecting Classes and Prototypes". Perspectives of Systems Informatics: 5th International Andrei Ershov Memorial Conference, PSI 2003, Akademgorodok, Novosibirsk, Russia, July 9-12, 2003, Revised Papers. p.  38.
  5. Trygve Reenskaug, Dept. of Informatics, University of Oslo, "The Case for Readable Code" (2007)
  6. Stein, Lynn Andrea. Delegation is Inheritance. OOPSLA '87 Conference proceedings on Object-oriented programming systems, languages and applications. pp. 138–146. doi:10.1145/38807.38820.
  7. Günter Kniesel (1999-11-19). "Type-Safe Delegation for Run-Time Component Adaptation". ECOOP' 99 — Object-Oriented Programming. Lecture Notes in Computer Science. Vol. 1628. Springer. pp. 351–366. CiteSeerX   10.1.1.33.7584 . doi:10.1007/3-540-48743-3_16. ISBN   978-3-540-66156-6. Archived from the original on 2015-03-04. Retrieved 2015-03-04. This paper proposes object-based inheritance (also known as delegation) as a complement to purely forwarding-based object composition. It presents a typesafe integration of delegation into a class-based object model and shows how it overcomes the problems faced by forwarding-based component interaction, how it supports independent extensibility of components and unanticipated, dynamic component adaptation.{{cite book}}: CS1 maint: bot: original URL status unknown (link)