Usuari:Kim-udg/Codi polimòrfic

De la Viquipèdia, l'enciclopèdia lliure

En programació, el polimorfisme (del Grec πολύς, polys, "molt, molts" i μορφή, morphē, "forma, figura") és una característica que permet donar a un mètode diferents formes, ja sigui en la definició com en la implementació.

Hi ha varis tipus genèrics de polimorfisme: el polimorfisme de sobre-càrrega (overload) i el polimorfisme de sobre-escriptura (override).

El polimorfisme de sobre-càrrega, consisteix a implementar diverses vegades un mateix mètode però amb paràmetres diferents, de tal manera que en invocar-lo, el compilador decideix quin dels mètodes s'ha d'executar, en funció dels paràmetres de la crida:

int entraElTeuPes (int pes) { .... codi1 .... }
int entraElTeuPes (String pes) { .... codi2 .... }

void funcio () {
entraElTeuPes (65); // Invonca el primer mètode executant el "codi1".
entraElTeuPes ("65"); // Invonca el segon mètode executant el "codi2".
}

El polimorfisme de sobre-escriptura, consisteix en re-implementar un mètode heretat d'una superclasse amb exactament la mateixa definició (incloent nom de mètode, paràmetres i valor de retorn). Això permet que en funció de la classe de pertinença d'un objecte, el compilador determini quin dels mètodes ha d'executar. (Recorda que la classe de pertinença correspon a la classe de la qual s'ha invocat el mètode constructor mitjançant la sentència "new").

class Clase1 {
metode1 () { ... codi 1 ... } }
class Clase2 extends Clase1 () {
metode1 () { ... codi 2 ... } }
Clase1 objecte1 = new Clase1 ();
objecte1.metode1 (); // Invoca el primer mètode executant el "codi 1".
Clase1 objecte2 = new Clase2 ();
objecte2.metode1 (); // Invoca el segon mètode executant el "codi 2".

Si una funció actua sobre el mateix tipus de variables, s'anomena polimorfisme de sobrecàrrega (o ad hoc). Aquest polimorfisme el suporten la gran majoría de llenguatges.

(Per exemple: es pot fer "i + j" amb "ints" o "floats")

En cas que la funció no contingui sigui de cap tipus en concret i, per tant, pugui ser utilitzada transparentment amb qualsevol nombre de nous tipus, s'anomena polimorfisme paramètric. En programació orientada a objectes, se'n sol dir programació genèrica. En la communitat de programació, aquest és el polimorfisme més habitual i se'n sol dir simplement polimorfisme.

Entenem com a subtipatje quan un nom pot denotar instàncies de diverses classes diferents, sempre que estiguin relacionades per alguna superclasse en comú. En programació orientada a objectes, aquest polimorfisme se'n sol dir polimorfisme a seques.

Història[modifica]

El polimorfisme Ad hoc i el paramètric van ser originalment descrits en els Conceptes Fonamentals en Llenguatges de Programació, un conjunt de notes escrites en 1967 per l'informàtic Britànic Christopher Starchey. En un diari de 1985, Peter Wegner i Luca Cardelli van introduir el terme de Polimorfisme d'inclusió per modelar subtipatges i herencia. No obstant, implementacions del subtipatge i herencia han aparegut prèviament amb el llenguatge de programació Simula, l'any 1967.

Tipus de polimorfisme[modifica]

Polimorfisme de sobrecarrega[modifica]

Chris Strachey va escollir el terme de polimorfisme ad hoc per fer referir-se a funcions polimòrfiques que poden ser aplicsades a arguments de diferent tipus, però que es comporten diferentment depenent del tipus d'arguments als que s'hi apliquin. El terme "ad hoc", en aquest context, simplement fa referència a el fet que aquest tipus de polimorfisme no és una característica fonamental del sistema tipològic. En el següent exemple, la funció Add sembla funcionar genèricament sobre diversos tipos quan s'hi fa les invocacions, però són considerafes dues funcions diferents pel compilador:

program Adhoc;

function Add( x, y : Integer ) : Integer;
begin
    Add := x + y
end;

function Add( s, t : String ) : String;
begin
    Add := Concat( s, t )
end;

begin
    Writeln(Add(1, 2));
    Writeln(Add('Hello, ', 'World!'));
end.

En llenguatges de tipología dinàmica, aquesta situació pot ser méx complexe ja que la funció que hauria d'incovar podria ser invocada únicament en temps d'exexcució.

La conversió de tipus implícita també està definida com a una forma de polimporfisme coneguda com "polimorfisme de coerció".

Polimorfisme paramètric[modifica]

El polimorfisme paramètric permet a una funció o tipus de dades que siguin escrites genèricament, d'aquesta manera, pot controlar valors idèntics sense dependre del seu tipus. El polimorfisme paramètric és una manera de fer un llenguatge més expressiu, tot mantenint la seva tipologia d'errors.

The concept of parametric polymorphism applies to both data types and functions. A function that can evaluate to or be applied to values of different types is known as a polymorphic function. A data type that can appear to be of a generalized type (e.g., a list with elements of arbitrary type) is designated polymorphic data type like the generalized type from which such specializations are made.

Parametric polymorphism is ubiquitous in functional programming, where it is often simply referred to as "polymorphism". The following example shows a parametrized list data type and two parametrically polymorphic functions on them:

data List a = Nil | Cons a (List a)

length :: List a -> Integer
length Nil         = 0
length (Cons x xs) = 1 + length xs

map :: (a -> b) -> List a -> List b
map f Nil         = Nil
map f (Cons x xs) = Cons (f x) (map f xs)

Parametric polymorphism is also available in several object-oriented languages, where it often goes under the name "generics" (for example, Java) or "templates" (C++ and D):

class List<T> {
    class Node<T> {
        T elem;
        Node<T> next;
    }
    Node<T> head;
    int length() { ... }
}

List<B> map(Func<A,B> f, List<A> xs) {
    ...
}

John C. Reynolds (and later Jean-Yves Girard) formally developed this notion of polymorphism as an extension to lambda calculus (called the polymorphic lambda calculus, or System F). Any parametrically polymorphic function is necessarily restricted in what it can do, working on the shape of the data instead of its value, leading to the concept of parametricity.

Subtyping[modifica]

Some languages employ the idea of subtyping to restrict the range of types that can be used in a particular case of polymorphism. In these languages, subtype polymorphism (sometimes referred to as inclusion polymorphism or dynamic polymorphism[cal citació]) allows a function to be written to take an object of a certain type T, but also work correctly if passed an object that belongs to a type S that is a subtype of T (according to the Liskov substitution principle). This type relation is sometimes written S <: T. Conversely, T is said to be a supertype of S—written T :> S.

In the following example we make cats and dogs subtypes of animals. The procedure letsHear() accepts an animal, but will also work correctly if a subtype is passed to it:

abstract class Animal {
    abstract String talk();
}

class Cat extends Animal {
    String talk() {
        return "Meow!";
    }
}

class Dog extends Animal {
    String talk() {
        return "Woof!";
    }
}

void letsHear(Animal a) {
    println(a.talk());
}

void main() {
    letsHear(new Cat());
    letsHear(new Dog());
}

In another example, if Number, Rational, and Integer are types such that Number :> Rational and Number :> Integer, a function written to take a Number will work equally well when passed an Integer or Rational as when passed a Number. The actual type of the object can be hidden from clients into a black box, and accessed via object identity. In fact, if the Number type is abstract, it may not even be possible to get your hands on an object whose most-derived type is Number (see abstract data type, abstract class). This particular kind of type hierarchy is known—especially in the context of the Scheme programming language—as a numerical tower, and usually contains many more types.

Object-oriented programming languages offer subtyping polymorphism using subclassing (also known as inheritance). In typical implementations, each class contains what is called a virtual table—a table of functions that implement the polymorphic part of the class interface—and each object contains a pointer to the "vtable" of its class, which is then consulted whenever a polymorphic method is called. This mechanism is an example of:

  • late binding, because virtual function calls are not bound until the time of invocation, and
  • single dispatch (i.e., single-argument polymorphism), because virtual function calls are bound simply by looking through the vtable provided by the first argument (the this object), so the runtime types of the other arguments are completely irrelevant.

The same goes for most other popular object systems. Some, however, such as Common Lisp Object System, provide multiple dispatch, under which method calls are polymorphic in all arguments.

Polytypism[modifica]

A related concept is polytypism or data type genericity. A polytypic function is more general than polymorphic, and in such a function, "though one can provide fixed ad hoc cases for specific data types, an ad hoc combinator is absent".[1]

See also[modifica]

Referències[modifica]

  1. Ralf Lammel and Joost Visser, "Typed Combinators for Generic Traversal", in Practical Aspects of Declarative Languages: 4th International Symposium (2002), p. 153.

Enllaços externs[modifica]