Polymorphism (programming)

from Wikipedia, the free encyclopedia

Polymorphism or polymorphism ( Greek for diversity ) is a concept in object-oriented programming that enables an identifier to accept objects of different data types depending on how it is used. In older typed programming languages , however, each name and each value in the source code of a program is assigned at most one type. This is known as monomorphism .

Types of polymorphism

Polymorphism of overloaded operators

An identifier that stands for an operator (e.g. "+", "-") can be implemented several times with a different meaning. The implementation must always be unique for each context in which the operator was newly declared.

Polymorphism of object-oriented programming

The polymorphism of object-oriented programming is a property that always occurs in connection with inheritance and interfaces . A method is polymorphic if it has the same signature in different classes but is implemented again.

If there are several methods in an inheritance branch of a class hierarchy at different hierarchy levels, but with the same signature , it is only determined at runtime which of the methods is used for a given object ( dynamic link ). Multilevel inheritance uses the method that is defined directly in the object class (i.e. the class of which the object is an instance), or the one that is furthest "down" in the inheritance branch (i.e. the method that is defined by the Inheritance is closest).

However, modern concepts also know polymorphism across class boundaries. The Objective-C programming language allows polymorphism between two methods of the same name , which are defined for the first time in different classes .

// NSObject kennt nicht -doSomething
@interface KlasseA : NSObject {
    
}
- (void) doSomething;
@end

@interface KlasseB : NSObject {
    
}
- (void) doSomething;
@end
// irgendwo
id object =  // Ein Objekt einer beliebigen Klasse
[object doSomething]; // polymorph zwischen KlasseA und KlasseB

The subclass before base class rule also applies here: If classB is derived from classC, the corresponding method of classC would be executed.

Polymorphism of a function or procedure

If the return value or an argument of a function is polymorphic, the function is called a polymorphic function. With the help of polymorphic functions, the genericity of data structures can also be used in algorithms .

Polymorphism of data types or classes

If a parameter for the data type actually used is passed for own data types or classes during instantiation or when calling the constructor , one speaks of parametric polymorphism , which semantically corresponds to genericity .

Further subdivisions

The following further subdivision is possible:

  • universal polymorphism
    • parametric polymorphism
    • Inclusion / Inheritance Polymorphism
  • Ad hoc polymorphism
    • Coercion
    • Overload

Sometimes ad hoc polymorphism is equated with overloading . This is due to Christopher Strachey , who was the first to subdivide polymorphism into parametric and ad hoc polymorphism.

Luca Cardelli and Peter Wegner expanded Strachey's concept to include inclusion polymorphism in order to model subtypes and inheritance. The above list thus reflects Strachey's classification, expanded to include the inclusion polymorphism of Cardelli and Wegner.

Universal and ad hoc polymorphism

Universal polymorphism differs from ad hoc polymorphism in several ways. With ad hoc polymorphism, a name or a value can only have a finite number of different types. These are also known during compilation . Universal polymorphism, on the other hand, allows an infinite number of types to be assigned.

Another difference is that the implementation of a universally polymorphic function generally executes the same code regardless of the types of its arguments, while ad hoc polymorphic (overloaded) functions can be implemented differently depending on the types of their arguments.

Overload and coercion

Functions are overloaded when different behaviors are associated with the same name. For example, the + operator is overloaded from the start in many programming languages . It can be used to add whole numbers and floating point numbers. It is also often used for string concatenation :

 42 + 3              (1)
 3.14 + 1.0          (2)
 "Hallo" + " Welt!"  (3)

Some programming languages differentiate between which names can and cannot be overloaded . Method overloading is allowed in Java , but operator overloading is not allowed except for the already built-in overload, such as the + operator. C ++ and some other languages ​​generally allow both.

Coercion is a kind of implicit type conversion , for example to convert arguments of a function into the types expected by the function. Coercion is closely related to overloading and differences are not necessarily immediately apparent to the programmer.

Example:

 3.14 + 2            (4)
 3 + 2.14            (5)

In a language, the addition operator could only be defined for two real numbers. Coercion would then ensure that whole numbers are converted into floating point numbers first . Coercion would then be used in (4) and (5). However, it is also conceivable that the addition operator is defined for several variants.

The overload is obviously not a real form of polymorphism, since one could imagine that the compiler would resolve the ambiguity by using a symbol several times at compilation time. So we only allow one symbol to denote different values, which however have different and possibly incompatible types.

It is similar with coercions. One could think that an operator accepts operands of different types (like the + above), but the types must first be converted for the operator. The output type of the operator is no longer related to the types of the operands (or only partially), so there can be no real polymorphism.

Parametric polymorphism

Parameterized polymorphism represents types whose definitions contain type variables. In Java one speaks of generic types or generics . Most modern object-oriented programming languages ​​support parametric type definitions, including Strongtalk (a variant of Smalltalk with a type system), C #, or Eiffel . In C ++ , generic types can be reproduced with the help of so-called templates .

Example:

  • monomorphic
TYPE iContainer IS ARRAY OF INTEGER;
  • polymorphic by type variable
TYPE Stack IS ARRAY OF [TYPVARIABLE]

Bounded parametric polymorphism

One differentiates fundamentally

  • simple parametric polymorphism and
  • constrained parametric polymorphism.

The latter solves the problems of type safety that arise within type definitions because when the type definition is created, due to the parameterization, it is not yet clear which type of object is actually the subject of the type operations (of the protocol, the methods, the terminology varies depending on Programming language) are. If, for example, a type defines a numeric operation that should be executable on the elements of the type, but its type variable is then assigned a non-numeric type, runtime errors would occur. As a rule, therefore, one uses restricted parametric types which specify a restriction to certain types for their type variables. In Strongtalk, for example, the type variable is specified using T <Supertype , where Supertype specifies the restriction of the types that can be used in the type variable T. Java allows such restrictions to be specified using the notation <T extends Supertype> .

Inclusion polymorphism

Inclusion polymorphism describes the property of being able to execute each method on a base type instead of on a subtype. Subtyping is therefore a form of inclusion polymorphism.

One distinguishes between:

  • Compilation time polymorphism (static binding)
    At compilation time the type of the object and thus the called function (also called "method") can be determined.

Examples

For example, suppose you want an application to display statistical data both graphically and in tabular form. It should also be possible to expand the display methods using plug-ins . Then the concept of polymorphism allows any implementation (here GraphDisplayPlugin , TextDisplayPlugin , HistogramDisplayPlugin ) to be called via the VisualizationPlugin interface .

The application itself does not have to be changed with new plug-ins and can simply be started via the interface by calling setData and display .

interface VisualizationPlugin {
    public void setData(DisplayData data);
    public void display();
}

class GraphDisplayPlugin implements VisualizationPlugin {
    public void setData(DisplayData data) { /* set data to be displayed */ }
    public void display() { /* Show Data as Graph */ }
}

class TextDisplayPlugin implements VisualizationPlugin {
    public void setData(DisplayData data) { /* set data to be displayed */ }
    public void display() { /* Show Data as table */ }
}

class HistogramDisplayPlugin implements VisualizationPlugin {
    public void setData(DisplayData data) { /* set data and calculate history data */ }
    public void display() { /* Show history data as Graph */ }
}

The following example in the programming language C # shows subtyping for the method calculateFlaecheninhalt () . The Rectangle and Triangle classes implement the method that declares the Polygon interface . The method gibFlaecheninhalt (Polygon polygon) can call the implementation of the method calculateFlaecheninhalt () for each subtype of the interface Polygon (see derived class ).

public interface Polygon
{
	double berechneFlaecheninhalt();
}

public class Rechteck : Polygon
{
	private double breite, hoehe;
	
	// Konstruktor
	public Rechteck(double breite, double hoehe)
	{
		this.breite = breite;
		this.hoehe = hoehe;
	}
	
	public double berechneFlaecheninhalt()
	{
		return breite * hoehe;
	}
}

public class Dreieck : Polygon
{
	private double a, b, c;
	
	// Konstruktor
	public Dreieck(double a, double b, double c)
	{
		this.a = a;
		this.b = b;
		this.c = c;
	}
	
	public double berechneFlaecheninhalt()
	{
		// Formel des Heron für den Flächeninhalt des allgemeinen Dreiecks
		return 0.25 * Math.Sqrt((a + b + c) * (-a + b + c) * (a - b + c) * (a + b - c));
	}
}

public static double gibFlaecheninhalt(Polygon polygon)
{
	return polygon.berechneFlaecheninhalt();
}

public static void Main(string[] args)
{
	double flaecheninhalt = gibFlaecheninhalt(new Rechteck(12, 16));  // flaecheninhalt = 192
	Console.WriteLine("Das Rechteck hat den Flächeninhalt " + flaecheninhalt);
	
	flaecheninhalt = gibFlaecheninhalt(new Dreieck(4, 13, 15));  // flaecheninhalt = 24
	Console.WriteLine("Das Dreieck hat den Flächeninhalt " + flaecheninhalt);
}

See also

literature

Individual evidence

  1. Computer Science. In: Duden. Mannheim 2001, ISBN 978-3-411-10023-1 , p. 496.
  2. Fundamental concepts in programming languages. Lecture notes for International Summer School in Computer Programming, Copenhagen, August 1967.
  3. On Understanding Types, Data Abstraction, and Polymorphism. In: ACM Computing Surveys. Volume 17, No. 4, 1985, pp. 471-522.