Article de reference

Polymorphisme (informatique)

En théorie des langages de programmation et en théorie des types , le polymorphisme permet à une valeur ou à une variable d'avoir plus d'un type et permet à une opération donnée...

théorie des langages de programmation et en théorie des types , le polymorphisme permet à une valeur ou à une variable d'avoir plus d'un type et permet à une opération donnée d'être effectuée sur des valeurs de plus d'un type.

En programmation orientée objet , le polymorphisme consiste à fournir une interface unique à des entités de types de données différents . Ce concept est emprunté à un principe de la biologie selon lequel un organisme ou une espèce peut présenter de nombreuses formes ou stades différents.

Les principales formes de polymorphisme les plus couramment reconnues sont :

  • Polymorphisme ad hoc : définit une interface commune pour un ensemble arbitraire de types spécifiés individuellement.
  • Polymorphisme paramétrique : ne spécifie pas de types concrets et utilise plutôt des symboles abstraits qui peuvent se substituer à n’importe quel type.
  • Sous-typage (également appelé polymorphisme de sous-type ou polymorphisme d'inclusion ) : lorsqu'un nom désigne des instances de nombreuses classes différentes liées par une superclasse commune.
L'intérêt pour les systèmes de types polymorphes s'est considérablement développé dans les années 1990, et les premières implémentations pratiques ont vu le jour à la fin de la décennie. Le polymorphisme ad hoc et le polymorphisme paramétrique ont été initialement décrits dans l' ouvrage de Christopher Strachey , *Fundamental Concepts in Programming Languages * où ils sont présentés comme les deux principales classes de polymorphisme. Le polymorphisme ad hoc était une caractéristique d' ALGOL 68 , tandis que le polymorphisme paramétrique constituait le cœur du système de types de ML .

Dans un article de 1985, Peter Wegner et Luca Cardelli ont introduit le terme polymorphisme d'inclusion pour modéliser les sous-types et l'héritage , citant Simula comme le premier langage de programmation à l'implémenter.

Formulaires

polymorphisme ad hoc

Christopher Strachey a choisi le terme de polymorphisme ad hoc pour désigner les fonctions polymorphes qui peuvent être appliquées à des arguments de types différents, mais qui se comportent différemment selon le type de l'argument auquel elles sont appliquées (également appelé surcharge de fonction ou surcharge d'opérateur ). « Ad hoc » signifie ici que cette forme de polymorphisme n'est pas une caractéristique fondamentale du système de types. Dans l' exemple Java ci-dessous, les addfonctions semblent fonctionner de manière générique sur deux types ( entier et chaîne de caractères ) lors de l'examen des appels, mais sont considérées comme des fonctions entièrement distinctes par le compilateur :

, x + y ); }public String add ( String name ) { return String.format ( " Ajouté" , name ) ; } }public class Adhoc { public static void main ( String [] args ) { AdHocPolymorphic poly = new AdHocPolymorphic ();System.out.println ( poly.add ( 1 , 2 ) ); // affiche " Somme : 3" System.out.println ( poly.add ( " Jay " ) ) ; // affiche " Jay ajouté " } }

Dans les langages à typage dynamique, la situation peut être plus complexe, car la fonction correcte à appeler ne peut être déterminée qu'à l'exécution.

La conversion implicite de type a également été définie comme une forme de polymorphisme, appelée « polymorphisme de coercition ».

polymorphisme paramétrique

Le polymorphisme paramétrique est un moyen de rendre un langage plus expressif tout en conservant une sécurité de type statique complète .

Le concept de polymorphisme paramétrique s'applique aussi bien aux types de données qu'aux fonctions . Une fonction qui peut s'évaluer ou s'appliquer à des valeurs de types différents est dite polymorphe. Un type de données pouvant se comporter comme un type généralisé (par exemple, une liste dont les éléments sont de types arbitraires) est qualifié de type de données polymorphe comme le type généralisé à partir duquel ces spécialisations sont effectuées.

Le polymorphisme paramétrique est omniprésent en programmation fonctionnelle, où il est souvent simplement appelé « polymorphisme ». L’exemple suivant en Haskell présente un type de données liste paramétré et deux fonctions polymorphes paramétriques sur ce type :

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) "
Liste de données a = Nil | Cons a ( Liste a )longueur :: Liste a -> Entier longueur Nil = 0 longueur ( Cons x xs ) = 1 + longueur xsmap :: ( a -> b ) -> List a -> List b map f Nil = Nil map f ( Cons x xs ) = Cons ( f x ) ( map f xs )

Le polymorphisme paramétrique est également disponible dans plusieurs langages orientés objet. Par exemple, les modèles en C++ et D , ou sous le nom de génériques en C# , Delphi , Java et Go :

John C. Reynolds (et plus tard Jean-Yves Girard ) ont formalisé cette notion de polymorphisme comme une extension du lambda-calcul (appelé lambda-calcul polymorphe ou Système F ). Toute fonction paramétriquement polymorphe est nécessairement restreinte dans ses propriétés, agissant sur la forme des données plutôt que sur leur valeur, ce qui conduit au concept de paramétricité .

Sous-typage

principe de substitution de Liskov ). Cette relation de types est parfois notée ; } }classe Chien étend Animal de compagnie { String parle () { return "Ouaf !" ; } }static void letsHear ( final Pet pet ) { System.out.println ( pet.speak ( ) ) ; }static void main ( String [] args ) { letsHear ( new Cat ()); letsHear ( new Dog ()); }

Dans un autre exemple, si `Number` , `Rational` et `Integer` sont des types tels que ''Rational''"}},"i":0}}] `Number :> Rational` et ''Integer''"}},"i":0}}] `Number :> Integer` ( Rational et Integer étant des sous-types d'un type `Number` qui est un supertype de ces types), une fonction écrite pour prendre un `Number` fonctionnera aussi bien avec un ` Integer` ou un `Rational` qu'avec un `Number` . Le type réel de l'objet peut être masqué aux clients et accessible via son identité . Si le type `Number` est abstrait , il peut être impossible d'accéder à un objet dont le type le plus dérivé est `Number` (voir type de données abstrait , classe abstraite ). Ce type particulier de hiérarchie de types est connu, notamment dans le contexte du langage Scheme , sous le nom de « tour numérique » et contient généralement beaucoup plus de types.

Les langages de programmation orientés objet offrent le polymorphisme de sous-type grâce à l' héritage (ou sous-classement ). Dans les implémentations classiques, chaque classe contient une table virtuelle (ou vtable ) – une table des fonctions implémentant la partie polymorphe de l'interface de la classe – et chaque objet contient un pointeur vers la vtable de sa classe, qui est consultée lors de l'appel d'une méthode polymorphe. Ce mécanisme est un exemple de :

  • liaison tardive , car les appels de fonctions virtuelles ne sont liés qu'au moment de l'invocation ;
  • dispatch unique (c'est-à-dire polymorphisme à un seul argument), car les appels de fonctions virtuelles sont liés simplement en parcourant la vtable fournie par le premier argument (l'thisobjet), de sorte que les types d'exécution des autres arguments sont totalement hors de propos.

Il en va de même pour la plupart des autres systèmes d'objets populaires. Certains, cependant, comme Common Lisp Object System , offrent la multidispatch , grâce à laquelle les appels de méthodes sont polymorphes pour tous leurs arguments.

L’interaction entre le polymorphisme paramétrique et le sous-typage conduit aux concepts de variance de type et de quantification bornée .

polymorphisme de lignes

les types structurels . Il permet l'utilisation de toutes les valeurs dont les types possèdent certaines propriétés, sans perte d'information sur les autres types.

Polytypisme

de programmation de tableaux , comme APL . L'essence du modèle de programmation polymorphe de rang consiste à traiter implicitement toutes les opérations comme des opérations d'agrégation, utilisables sur des tableaux de dimensions arbitraires , ce qui signifie que le polymorphisme de rang permet de définir des fonctions opérant sur des tableaux de toute forme et de toute taille.

Aspects de mise en œuvre

Polymorphisme statique et dynamique

fonction virtuelle ). On parle respectivement de dispatch statique et de dispatch dynamique , et les formes correspondantes de polymorphisme sont appelées polymorphisme statique et polymorphisme dynamique .

Le polymorphisme statique s'exécute plus rapidement, car il n'y a pas de surcharge liée à la répartition dynamique, mais il nécessite une prise en charge supplémentaire du compilateur. De plus, il permet une analyse statique plus poussée par les compilateurs (notamment pour l'optimisation), les outils d'analyse de code source et les programmeurs. Le polymorphisme dynamique est plus flexible, mais plus lent ; par exemple, il permet le typage dynamique (ou « duck typing » ) et une bibliothèque liée dynamiquement peut manipuler des objets sans connaître leur type complet.

Le polymorphisme statique se rencontre généralement dans le polymorphisme ad hoc et le polymorphisme paramétrique, tandis que le polymorphisme dynamique est courant pour le polymorphisme de sous-type. Cependant, il est possible d'obtenir un polymorphisme statique avec sous-typage grâce à une utilisation plus sophistiquée de la métaprogrammation par modèles , notamment le modèle curieusement récurrent .

Lorsque le polymorphisme est exposé via une bibliothèque , le polymorphisme statique devient impossible pour les bibliothèques dynamiques , car il est impossible de connaître les types des paramètres lors de la construction de l' objet partagé . Alors que des langages comme C++ et Rust utilisent des modèles monomorphes , le langage de programmation Swift recourt largement à la répartition dynamique pour construire par défaut l' interface binaire de l'application pour ces bibliothèques. De ce fait, davantage de code peut être partagé pour une taille système réduite, au prix d'une surcharge d'exécution.