POO vs programmation fonctionnelle

Les langages fonctionnels, comme Go ou Clojure, semblent avoir le vent dans les voiles ces temps-ci. Quel est l’avantage à ne pas utiliser d’objets?

1 « J'aime »

(Attention : je ne développe pas moi-même en fonctionnel)

Pour moi, l’avantage est la prévisibilité du code : si on ne gère pas d’objets, on ne gère pas d’états, de mutabilité, et chaque unité de code se préoccupe d’une seule chose sans risque d’avoir des effets de bord. Pour certains langages fonctionnels, la compilation a un rôle de validation des types très important, de sorte à pouvoir quasiment garantir le bon fonctionnement d’un programme s’il parvient à compiler.

Tu veux dire que les intérêts de la prog fonctionnelle pourrait être utilisé en POO si l’on suit des (bonnes) pratiques ? C’est tout à fait possible de faire en sorte d’avoir des objets sans effets de bord.

Pas tout à fait : l’idée même d’un objet est d’être mutable, d’avoir un état. C’est à contre-courant de la philosophie fonctionnelle : certains (la plupart ?) langages ne permettent pas la création de variables au sens propre du terme : on peut bien sûr stocker une valeur, mais elle n’est pas mutable, ce qui force à déterminer une nouvelle valeur, qui la remplacera éventuellement.

J’aimerai l’avis de quelque qui utilise les deux. Est-ce qu’il y voit un réel avantage et dans quel type de programme?

Pour du traitement de données pur, tu n’as pas d’état à gérer et la programmation fonctionnelle prend tout son sens à mes yeux.
De plus en plus de langages intègrent des concepts issus de la programmation fonctionnelle, notamment par la présence de higher-order functions du type map, fold… qui permettent d’écrire plus facilement ces traitements.

Clairement je pense que bien souvent on oppose OO à fonctionnel alors que les deux ne sont pas incompatible. Le Scala par exemple gère bien le mélange des deux paradigmes. mais d’autre langages fonctionnel même si ils n’ont pas la notions d’objets, propose des mécanismes équivalent. Et on peut très bien faire du fonctionnel avec des langages OO même si la mise en place peut parfois être plus compliqué

1 « J'aime »

Pensez-vous qu’il y a une plus-value à apprendre un langage fonctionnel même quand on reste dans un langage objet comme Python ou Ruby ? Pour reformuler, est-ce qu’apprendre un autre langage améliore ces compétences dans le premier ?

Je suis convaincu que oui car ça t’apprend à réfléchir différemment (en terme de fonctions, de récursivité…).
Pour ceux qui souhaitent s’initier à la programmation fonctionnelle, le cours d’initiation à Scala sur Coursera est vraiment intéressant (sa suite l’est un peu moins à mes yeux).

2 « J'aime »

Dans Ruby ou Python tu as déjà des éléments liés à la FP, moi c’est ce qui m’a sensibilisé. Par exemple plutôt qu’implementer un template method avec un héritage, pourquoi ne pas passer des fonctions en paramètre de fonction ?
En python tu peux coupler de generator à de la list comprehension pour écrire des traitements simples et lisibles de conversion et filtrage de données.
En java, tu peux le faire aujourd’hui en 1.8 mais c’est tout nouveau.
Maintenant j’ai bien envie d’approfondir.

1 « J'aime »

Bonjour,
Je précise d’emblée que je pratique les deux paradigmes : Java et POO depuis 17 ans, Haskell et PF depuis 14 ans… Pfff, on se sent vieux d’un coup. Pour avoir pratiqué les deux donc, le principal avantage du paradigme fonctionnel dans sa version fortement typée et pure (aka. Haskell, ML & Co.) est la simplicité.

Je sais, ça peut paraître un peu paradoxal car ces langages ont la réputation d’être difficiles à apprendre, mais en fait c’est faux. Il y a un et un seul concept à comprendre pour pouvoir les utiliser, c’est celui de fonction

f :: a -> b,
une entité permettant d’associer de manière univoque et constante chaque élément d’un domaine à un élément d’un codomaine, autrement dit une fonction totale au sens mathématique du terme. Notons que l’immutabilité est une conséquence logique de ce principe fondateur : si tout ce que j’ai à ma disposition c’est des fonctions (au besoin d’arité 0), alors je ne peux jamais modifié quoi que ce soit, je ne fais que produire de nouvelles valeurs.

En POO, tu as (au moins) deux concepts : les objets, et les méthodes de ces objets, autrement dit des fonctions dont le premier paramètre est une instance d’un certain type. Et dans la plupart des langages, à l’exception notable de Javascript, tu as en plus le concept de classe. Smalltalk qui est le premier langage vraiment orienté-objet, avait unifié tout cela dans le paradigme “envoi de message” : tout élément du langage devenait une expression formée d’un objet, et d’un message envoyé à cet objet. Mais cette élégance a disparue dans ses successeurs et concurrents…

Cette simplicité, en apparence banale, est extrêmement puissante quand tu te rends compte que le domaine ou le codomaine d’une fonction peut être lui même une fonction : je peux définir des fonctions qui prennent en paramètre des fonctions et qui construisent des fonctions qu’elles retournent. Une des conséquences les plus évidentes en est qu’il n’y pas de limite autre que l’expressivité à la factorisation du code : tout fragment de code dupliqué peut être factorisé dans une fonction ou une expression partagée.

Une autre conséquence moins évidente est la possibilité de construire des abstractions à l’infini. En POO en Java, je suis limité par les structures du langage : méthode, objets, classes, éventuellement méta-classe. La tour d’abstraction s’arrête quelque part et si j’ai un concept qui subsume plusieurs méta-classes par exemple, je ne peux pas construire une meta-meta-classe. Ce que je fais du coup c’est souvent de faire un pas de côté et d’utiliser la réflexion. Mais je sors alors du langage, je perds toute sécurité offerte par le compilateur ou l’interpréteur… En PF, je n’ai pas de limite puisque j’ai un seul concept malléable à l’extrême.

Je ne fais qu’égratigner la surface des choses, il faudrait aussi parler des spécificités de chacun des langages car il n’y a pas une PF mais des PF: il y a de grandes différences entre les familles LISP, ML et Erlang par exemple.

4 « J'aime »

L’éternel sujet POO vs. fonctionnel. Je reste d’avis que les deux paradigmes ne sont pas là pour s’opposer mais pour se compléter. Un bon ingénieur utilisera le bon outil pour résoudre le bon problème.

Le problème résolu par la PF ? A mon sens, tout ce qui est traitement séquentiel ou parallèle des données.
Le problème résolu par la POO ? A mon sens la structuration de l’architecture du programme.

J’ai tendance à pas mal utiliser Groovy depuis quelques années et y mêler POO et PF, sans chercher à être un puriste d’une approche ou d’une autre. J’essaye d’ailleurs, (via code, formations en fac, formations en clientelle, articles, …) de partager une vision pragmatique de la programmation où le mot d’ordre est : essaye de rédiger un code simple et naturel pour que le plus grand nombre puisse comprendre plutôt que de t’orienter vers de la masturbation intellectuelle compréhensible que par ceux qui se creuseront la tête pendant plusieurs minutes.

J’ai appris d’abord la POO voilà 15 ans, puis le fonctionnel voilà 10 et depuis 5 ans je me suis rendu compte que je fonctionne sur un mode un peu intermédiaire. Au final je dirais que j’ai un style beaucoup plus restreint que la verbeuse POO sans aller jusqu’à la pureté guindée du fonctionnel.

Je pense que j’ai été pas mal influencé par le style d’Alexander Stepanov, créateur du la STL du C++, dont vous trouverez un aperçu dans cet interview, sur le même thème : http://www.stlport.org/resources/StepanovUSA.html

Je viens de regarder cette vidéo sur Haskell. Ça résume ce qu’il c’est dit ici mais c’est payant malheureusement.

D’après ce que je comprend, la PF utilise des fonctions qui sont plus proche du sens mathématique. Une fonctionne accepte des arguments et retourne un résultat dans modifier les arguments passé. Donc, il n’y a aucun “Side effect”. La PF est très bonne pour gérer des données rapidement étant donné qu’il faut entrer une valeur et obtenir un résultat. Le programmation fonctionnel est rapide étant grâce à l’immutabilité. Il n’y a pas besoin d’utiliser de Garbage Collector, etc.

La POO, quant-à-elle, est plus approprié pour la programmation d’application plus complexe nécessitant une plus grosse architecture.

Est-ce que j’ai bien compris?

1 « J'aime »

La question n’a pas vraiment de sens selon moi, car bien que les deux soient des paradigmes ils ont des buts différents. On ne peux pas programmer qu’en POO ça n’existe pas, pour faire des méthodes (fonctions) tu peux utiliser un algo avec des variables et des boucles : ça s’appelle l’impératif ; ou bien une fonction récursive avec des constantes, ça s’appelle le fonctionnel.

La POO n’est là que pour organiser le code, et remplacer des tableaux multidimensionnels où on se mélange les pinceaux par une abstraction via des objets qui évoluent, ce qui parle plus à un être humain.

Malheureusement beaucoup de langages comme python ou php n’optimise pas le fonctionnel, et il a souvent bien des avantages face à l’impératif (mis a part le temps de calcul qui diffère un peu en général), comme la lisibilité du code (parfois on a presque l’impression d’écrire un poème tellement c’est beau !), et la simplification de la création de l’algo, qui demande peut-être un peu plus de réflexion et d’entraînement auparavant. Il y a plein d’exemples de code sur Internet pour comparer je ne vais pas les poster ici.

Pour ma part j’ai appris avec Racket, plutôt connu dans les filières informatique à l’université. Il est multi-paradigme, très puissant, et optimise la récurrence. Le meilleur moyen reste de se faire son propre avis :)
http://racket-lang.org/

Human Coders - Le centre de formation recommandé par les développeur·se·s pour les développeur·se·s