POO vs Composinting

Si vous vous êtes intéressé au langage “Go”, alors vous devez savoir qu’il n’est pas un langage purement objet mais “de compositing”. Mais quand vous codez en Go, vous avez cette impression de coder avec des classes et des objets. Alors c’est quoi la différence ?

On va se réferer à la page de FAQ: https://golang.org/doc/faq#Is_Go_an_object-oriented_language et on lit:

Is Go an object-oriented language?

Yes and no. Although Go has types and methods and allows an object-oriented style of programming, there is no type hierarchy.

La réponse peut paraitre claire pour certains, pourtant la mailing-list est bourrée de la même question, “mais je comprend pas la différence puisqu’on peut hériter et utiliser des objets”. La phrase peut paraitre sensée mais elle est en opposition avec la réponse donnée dans la FAQ.

Pour comprendre, il faut comparer Go avec un autre langage. On va utiliser Python, et faire de l’instrospection de type. Dans cet exemple, on va créer une classe Foo qui sait retourner le nom de la classe (donc “Foo”) et la dériver en Bar.

Ok, donc en appelant la méthode “name” de l’instance de classe Bar, on appelle la méthode définie dans la classe “Foo”. Mais le résultat est bon: l’instance de classe Foo répond par “Foo” et l’instance de Bar répond par “Bar”.

Faisons la même chose avec Go.

Là, ça marche plus… Les deux appels retournent “*main.Foo” !

Mais pourquoi donc ?

Le fait est que Go utilise le modèle “composite”, ce qui veut dire que la définition de Bar contient une instance de Foo. Clairement, Bar n’hérite pas de Foo. Bar transporte une variable de type Foo (ou *Foo) dont on peut utiliser les méthodes sans utiliser le nom de variable. Mais en réalité, ce qu’il s’est passé, c’est que nous avons appelé “new(Bar).Foo.Name()” - et c’est très différent de l’héritage. Et on retrouve la réponse donnée dans la FAQ: les types n’héritent pas les uns des autres.

Alors qu’en Python, Bar a hérité de la méthode “name”. Cela induit que Bar “réplique” la méthode pour son propre compte.

En d’autres termes, il n’est pas possible pour une méthode de structure Foo, de connaitre la signature des objet “enfants”.

C’est pour cela que le développement en Go “ressemble” à de la POO sans en être réellement.

Et si vous pensez que ce modèle n’est pas une bonne idée, sachez qu’il a un sacré nombre d’avantages. Entre autre, le polymorphisme est plus facile à gérer, car en composant une structure avec d’autres structures, je peux m’assurer que la méthode que j’appelle provient bien du bon type qui la compose en appelant explicitement la méthode avec le nom du type inclu.

Autre intérêt, je peux modifier l’instance du type qui est inclu ou encore l’enregistrer dans une autre instance. Ce qui veut dire que je peux faire en sorte que deux instances de Bar ait des propriétés différentes, mais qu’un appel à la méthode de Foo utilise le même “objet”.

Et j’en passe.

Donc, certes, quand on est habitué à de la POO traditionnelle tout cela peut être déroutant, mais avec l’habitude on trouve son compte dans le modèle composite, et on trouve même ça très pratique. Ce n’est donc pas un défaut, ni une atout, c’est juste un design de langage différent avec ses spécifités à maitriser.

comments powered by Disqus