Paradigme – introduction

Si vous avez eu l’occasion de pratiquer plusieurs langages de programmation, c’est que vous avez sûrement déjà utilisé de nombreux paradigmes de programmation. Vous en avez même probablement utilisé plusieurs dans un seul et même langage. Mais qu’est ce que cela signifie ? Un paradigme de programmation est une façon de faire, un style global de programmation mettant en œuvre une approche particulière pour concevoir la résolution d’un problème. Concrètement, il s’agit de la réunion d’un ensemble de concepts.

Les principaux paradigmes de programmation auxquels vous aurez à faire sont l’impératif, le déclaratif et le structuré. Il existe cependant de nombreuses relations et parfois une certaine hiérarchie  entre paradigmes. Par exemple le paradigme déclaratif est parent du fonctionnel et du logique, tandis que l’orienté objet qui découle du structuré peut être associé avec le fonctionnel (OCaml, F#) ou l’impératif (C#, Java).

Exemples de paradigmes

  • Avec le paradigme impératif, on décrit pas à pas comment arriver à notre solution, comme une recette de cuisine.
  • Avec le déclaratif, comme son nom l’indique, on écrit pas des instructions mais des déclarations, un paradigme sous-jacent au déclaratif est par exemple le descriptif (XML, JSON).
  • Avec le paradigme fonctionnel, on décrit le quoi, ce qu’on veux et non comment y arriver. Il s’agit d’un paradigme sous-jacent au déclaratif.
  • Avec le paradigme logique, on décrit aussi le quoi mais plus directement on décrit notre problème, on le formalise, et c’est à la machine de trouver comment le résoudre.

 

Impératif

L’impératif est un paradigme dans lequel un programme consiste en une suite d’instructions exécutées pas à pas, modifiant l’état du programme via les divers affectation et modifications des valeurs des variables. Pour résumer, l’impératif est basé sur la modification d’état on peut dire qu’il fonctionne grâce aux effets de bords. C’est d’ailleurs ces mêmes effets de bords qui provoquent le plus d’erreurs à l’exécution. En effet il suffit qu’une valeur à un instant t1 soit mal géré pour qu’elle implique un comportement du programme inadéquat à un instant t2 qui est difficilement prévisible. Au delà de ça, l’impératif est très intuitif et la modification in-place de variable est généralement plus rapide qu’une copie.

Fonctionnel pur

A contrario, un des traits les plus marquant du fonctionnel pur est qu’il exclu toute modification d’état. Une fois qu’une variable est assignée, elle ne peut changer de valeur. Ce simple fait permet d’exclure tout effet de bord, de permettre au compilateur certaines optimisations. En fait, ce paradigme se rapproche énormément des mathématiques, car dans ce paradigme une fonction est équivalente à une fonction mathématique. Pour une entrée donnée x elle fournira toujours la même sortie y. Il y est exclu toute notion de non déterminisme.

Attention, il existe des langages fonctionnels et impératifs comme OCaml, les deux ne sont pas incompatibles, on dira par contre qu’il s’agit d’un langage fonctionnel non pur puisqu’il autorise les effets de bord.

Objectifs

Un paradigme de programmation peut avoir de nombreux objectifs :

  • Par la syntaxe qu’il induit, réduire les lignes de code et assurer une meilleure maintenance.
  • Par les effets qu’ils procure, améliorer la sûreté d’exécution d’un programme ou permettre des optimisations au niveau de la mémoire ou de performance à l’exécution ou / et à la compilation.
  • Améliorer la productivité du développeur.
  • Permettre de traiter des catégories de problèmes de la façon la plus adaptée.
  • Offrir une vision et une philosophie différente sur l’approche à adopter pour la résolution d’un problème.
  • Introduire le support cohérent d’un ensemble de concepts pour un langage.

 

Chaque paradigme de programmation répond à des attentes et à des besoins différents. Les utiliser tous en même temps n’est pas concevable et bien que certain puissent être complémentaires, ils ne sont pas forcément tous compatibles et en faire un mélange hasardeux peut réduire le pouvoir et la force de l’un d’entre eux, voir de tous, si aucune cohérence n’est assurée quant par leur support (le langage).

Apprendre et comprendre différents paradigmes de programmation est un très bon exercice pour apprendre à penser et à voir un problème ainsi que sa résolution de différentes manières.

Relation entre langages et paradigmes

La nature même d’un langage de programmation, sa syntaxe, sa logique, ses concepts et les opérations qu’il autorise implique un paradigme général qui lui est sous-jacent. Mais la plupart des langages populaires supportent plusieurs paradigmes, par exemple Java ou C# supportent à la fois l’impératif, le structuré, le procédural, le modulaire par le biais de l’orienté objet, la conduite par les événements, etc… Ils dégagent généralement un paradigme principal sur lequel s’articulent les autres, ici par exemple la POO (Programmation Orientée Objet) impérative.

D’autres langages sont conçus expressément pour ne supporter (globalement) qu’un seul paradigme, c’est le cas par exemple de Haskell et de Miranda qui supportent uniquement le paradigme fonctionnel ou de Smalltalk qui supporte uniquement le paradigme objet, on dit qu’ils sont purs.

Certains langages quant à eux, supportent de nombreux paradigmes dans une unité globale cohérente, on dit qu’ils sont multi-paradigmes. Un très bon exemple étant le langage Oz où l’utilisateur pioche selon les besoins dans les différents concepts sous-jacent à ses paradigmes. Ainsi comme exemple, Oz propose par défaut une évaluation stricte, mais le mot-clé lazy permet une évaluation différée des valeurs, il propose l’utilisation de l’orientée objet, du fonctionnel, etc. le tout dans un cadre cohérent.

Dual-paradigm

Appliquer vs implémenter un paradigme

Rien n’empêche sous certaines conditions à l’utilisateur de se conformer à un style de programmation particulier afin d’appliquer ou d’implémenter un paradigme non natif au langage utilisé, comme par exemple, faire de la programmation fonctionnelle en JavaScript ou encore de l’objet en C. Je précise, sous certaines conditions, car cela nécessite tout de même que le langage en question offre les concepts et dispose des opérations adéquates pour son implémentation.

Bien qu’un paradigme puisse être en surface porté par une API (ce qui est le cas quand on applique le paradigme fonctionnel en JavaScript), il est recommandé pour parler rigoureusement de paradigme, que celui-ci (ses concepts) soit déterminé par le langage lui-même (ce qui est le cas lorsque l’on implémente le paradigme). Le fait qu’il soit porté par le noyau du langage lui assure un support concret, notamment par la restriction du jeu d’instruction et des opérations autorisées en vue de maintenir le ou les paradigmes du langage dans une cohérence globale, assurer un support au niveau de sa compilation permettant des optimisations, la vérification statique d’erreurs, etc.

Par exemple, il ne sera pas possible d’assurer un support cohérent du paradigme fonctionnel pur en JavaScript par le biais d’une API par le simple fait que ce langage supporte avant tout le paradigme impératif. Le fonctionnel pur  – n’autorisant pas la modification d’état – étant mutuellement exclusif de l’impératif – basé sur la modification d’état -.

Ce sont les paradigmes associés à un langage qui définissent le cadre de l’utilisation où il est le plus adapté et le type de problèmes qu’il permet de résoudre au mieux et non l’inverse.

 

Après cette brève présentation de ce qu’est un paradigme, je vous invite à lire le prochain article sur le paradigme impératif.


Laisser un commentaire