philippe-dunski

philippe-dunski

Vite dit


Java: sale menteur!

L'autre jour, je discutais avec l'un de mes javaistes d'amis.  Après tout, il y a des gens très bien qui développent en java!

Bien sûr, comme je suis plutôt orienté vers le C++, la discussion n'a pas traîné à dériver sur les avantages comparés de java et de C++.  C'est le coup classique!

Lorsque j'en suis arrivé à discuter de l'héritage multiple, il s'est écrié: "Héritage multiple, bons dieux, quelle horreur!". 

J'ai alors pris un exemple classique : Comment créer une classe TurboGenerateur lorsqu'on dispose d'une classe Turbine et d'une classe Generateur ? Après tout, LSP est parfaitement respecté si l'on décide de faire hériter notre classe TurboGenerateur de Turbine et de Generateur, vu qu'un tel objet est, bel et bien, tout à la fois une turbine et un générateur et que l'on retrouve bel et bien, au niveau de TurboGenerateur, tout ce que l'on trouve aussi bien dans l'une que dans l'autre.

- "Et les interfaces, c'est fait pour les cochons? m'a-t-il répondu."

- "Bien sur que non, mais si on a deux développeur -- l'un qui décide de mettre l'accent sur l'aspect Turbine, implémentant également l'interface IGenerateur et l'autre qui décide de mettre l'accent sur l'aspect Generateur, implémentant également  l'interface ITurbine-- on fait quoi?" lui demandai-je. "On se retrouve avec deux classes totalement différentes, qui font exactement la même chose, mais qu'on ne peut pas substituer l'une à l'autre?"

Il m'a alors expliqué que, si Turbine implémentait l'interface ITurbine et que Generateur implémentait l'interface IGenerateur, il n'y aurait aucun problème : la substitution pourrait parfaitement se faire aussi bien en transmettant une ITurbine qu'un IGenerateur.  Il a, sur ce point, totalement raison!

Il faut alors se rendre compte que, lorsque vous décidez en java qu'une de vos classe implémente une interface, vous ne faites rien d'autre que de créer une relation d'héritage au termes du LSP.  Bien sur, votre interface ne fait qu'exposer des comportements "à définir dans la classe qui les implémente", mais il n'y a aucune différence -- hormis le mot clé utilisé pour la définir (interface au lieu de class) -- entre une interface et une classe.

Enfin, ce n'est pas tout à fait vrai, dans le sens où vous devrez utiliser le mot clé inherits pour faire hériter votre classe particulière d'une classe donnée et le mot clé implements pour faire en sorte que votre classe particulière implémente une interface donnée.

Mais un fait demeure : il n'y a, conceptuellement parlant, aucune différence aux termes de LSP entre la relation qui unit une classe dérivée à la classe de base déclarée à l'aide du mot clé inherits et la relation qui unit une classe dérivée et l'interface implémentée à l'aide du mot clé implements.

La seule différence qui existe n'est jamais qu'une différence "artificielle" imposée par java au travers des différents mots clé.

La conclusion logique, c'est que java vous ment lorsqu'il vous impose d'éviter l'héritage multiple! Chaque fois que vous décidez de faire hériter une classe d'une autre et de lui faire implémenter une interface, ou chaque fois que vous décidez qu'une classe implémente plusieurs interface, vous ne faites absolument rien d'autre que créer des relations d'héritage multiple!

Amis javaistes, pensez à cela avant de vous lancer dans une diatribe contre l'héritage multiple : vous en êtes très certainement les plus gros utilisateurs.  Votre langage préféré l'a élevé au rang d'institution en créant la notion d'interface. La seule chose, c'est que vous n'en avez peut être pas conscience à cause des mots clés que vous utilisez.


16/01/2014
7 Poster un commentaire

C++, multi-paradigme? non, multi optiques, au mieux

Bjarne Stroutrup a bien raison de ne pas aimer entendre parler de "langage muti-paradigme" lorsqu'on parle de C++.  En effet, selon wikipedia, un paradigme est une représentation du monde, une manière de voir les choses, un modèle choérent de vision du monde <...> une forme de rail de la pensée dont les lois ne doivent pas être confondue avec celles d'un autre paradigme.

Autrement dit, si l'on en croit wikipedia, à partir du moment où l'on a décidé d'un paradigme pour le développement d'un projet, on devient véritablement l'esclave de cette décision, sans retour en arrière et sans compromis possible.

Cela se remarque entre autres pour des langages comme java ou comme C# qui obligent à créer une fonction membre, statique, nommée main pour au minimum une classe et ce, même si cette fonction devait être la seule fonction de cette classe. Ces langages appliquent à la lettre la définition d'un paradigme telle qu'elle est donnée par wikipedia et considèrent que "tout est objet".  Même leur generics (ou ce qui en tient lieu) sont, d'abord et avant tout apparentés des objets, bien que le développeur puisse ne pas forcément en avoir conscience.

Le gros malheur, c'est que cette approche "formate" le schéma de pensée de nombreux développeurs, y compris celui de développeurs qui ne sont pas soumis aux restrictions d'un paradigme unique : Combien de fois n'assistons nous pas à une discussion dans laquelle un intervenant vient nous asséner un "Mais pourquoi ne fais tu pas une classe?" ou un "Mais tu dois penser en termes d'objets" ?

En C++, de telles affirmations perdent beaucoup de leur sens.  N'allez pas me faire dire ce que je n'ai pas dit : il arrive très régulièrement qu'elles soient parfaitement sensées dans une situation particulière bien spéciale.  Mais il arrive aussi très régulièrement qu'un des "autres paradigmes" proposé par C++ fasse aussi bien l'affaire, sinon mieux.

Je pense bien sûr au paradigme générique, mais on peut aussi compter sur le paradigme purement procédural.

Je conseillerais donc au lecteur de ce ticket d'accepter l'éventualité que le paradigme orienté objet -- qui apporte il est vrai beaucoup de réponses -- puisse ne pas être adapté à toutes les situations, et d'accepter d'élargir ses horizons afin d'accepter d'envisager le paradigme procédural et le paradigme générique de la même manière que l'orienté objet.  Vous aurez tout à y gagner, car vous pourrez alors choisir "le meilleur" de chaque paradigme, et vos développements seront plus faciles à maintenir, à corriger et à faire évoluer.


14/01/2014
1 Poster un commentaire