OCaml et moi, une grande histoire d’amour

Bonjour à toutes et à tous,

Cela fait maintenant plus d’un an que j’ai découvert OCaml, et mon affection pour ce langage grandit jour après jour, à tel point que je trouve nécessaire d’écrire un billet afin de vous raconter comment, et surtout pourquoi, je suis tombé amoureux.

See original image

« De toutes façons, les langages sont tous pareils. »

Cette pensée a probablement dû vous traverser l’esprit au moins une fois dans votre vie, lorsque, au cours d’un énième cours sur tel ou tel langage de programmation, on vous explique comment créer une variable, réaliser une boucle, déclarer une fonction. C’est également cette pensée que j’avais formulée sur un forum où quelqu’un demandait un avis sur un premier langage à apprendre.

« De toutes façons, les langages, ils sont tous pareils. On déclare des variables, on fait des boucles. Rien de nouveau sous le soleil, quoi.
– Tu connais la programmation fonctionnelle ?
– Non, qu’est-ce que c’est ?
– Je te laisse te renseigner sur OCaml, tu verras. »

Ni une ni deux, j’avais enfourché mon fidèle destrier Google, et je partis en quête de ce langage qui ne serait pas « comme les autres ».

See original image
Quelque soit votre métaphore, Google a un doodle qui convient.

Et ce que j’ai trouvé, vous vous en doutez, m’a subjugué.

Le but de cet article n’est pas de présenter OCaml, encore moins de réaliser un cours sur la programmation fonctionnelle. Si vous voulez en savoir plus, je vous laisse partir en quête à votre tour. A la place, ce que je me propose de faire, c’est de mettre en lumière quelques aspects d’OCaml qui en font vraiment, selon moi, un langage d’exception.

Performance, sécurité, élégance

Ces trois mots constituent, à mon sens, les trois idéaux vers lesquels un langage de programmation devrait toujours tendre.

La performance, parce qu’en notre époque, bien que les ordinateurs deviennent de plus en plus puissants, il s’agit d’une problématique critique dans de plus en plus de domaines ; big data, machine learning, objets connectés ont tous besoin de programmes qui s’exécutent vite et bien.

La sécurité, tant du point de l’utilisateur qui ne veut pas se faire pirater son compte en banque, que du point de vue du développeur qui veut s’assurer que son programme s’exécute sans accroc.

L’élégance, parce qu’un bon code est un code simple, et parce qu’aujourd’hui, on doit pouvoir reprendre et relire un programme sans avoir à naviguer dans un code alambiqué au possible.

Lorsque j’ai démarré avec OCaml, j’ai été incroyablement surpris de voir que tous les livres, les cours, les diaporamas que j’ai pu trouver sur Internet faisait mention à cette trinité en expliquant telle ou telle technique, tel ou tel élément de syntaxe. Et effectivement, aujourd’hui, je me rends compte qu’OCaml est un langage qui a été développé pour répondre à ces problématiques, et je trouve ça admirable.

Exemple

Le typage d’OCaml est sans aucun doute le plus strict qu’il m’ait été donné de voir jusqu’à présent. D’aucuns le qualifieraient de rigide, voire de tyrannique, mais je préfère dire intransigeant. Encore une fois, je ne veux pas m’épancher sur le sujet, je vous laisse le soin de vous renseigner, mais voici ce qu’OCaml nous dit.

# 2 * 2.5;;
Error: This expression has type float but an expression was expected of type int

Vous avez bien lu, OCaml est incapable de multiplier un entier et un flottant sans un cast explicite. Vous vous en doutez, il y a une raison à ça : OCaml fait de l’inférence de type. Ce qui signifie que vous, en tant que développeur, n’avez pas à déclarer le type de vos variables (élégance) mais que tous les types sont vérifiés par le compilateur et que la moindre erreur de type vous est remontée à la compilation (sécurité).

L’exemple que je donne tout le temps est celui du nom d’utilisateur et du mot de passe. Les deux sont des chaînes de caractères, mais représentent des choses différentes. Admettons qu’un développeur fasse une erreur et compare un nom d’utilisateur et un mot de passe. Ca n’a aucun sens, mais la plupart des langages laisseront passer cette écriture, certains langages émettront peut-être un warning. OCaml, quant à lui, ne laissera pas passer cette erreur à la compilation, avec un message du même goût que celui ci-dessus. Et ça, si vous voulez mon avis, c’est beau.

La versatilité

Que ce soit dans l’implémentation ou dans la compilation, OCaml est un outil qui laisse pas mal de liberté au développeur. Par exemple, le simple fait qu’un programme puisse être compilé vers du code natif, compilé vers du bytecode, ou même interprété, donne au développeur différentes options : selon le cas, on préfèrera la performance du code natif, ou la portabilité du bytecode, ou la légèreté de l’interprété. Vous trouverez plus d’informations à ce sujet ici. Autre exemple, la bibliothèque standard d’OCaml. Celle-ci est particulièrement bien fournie comparée à certains autres langages, mais si l’envie vous en prend, vous pouvez la surcharger pour y ajouter d’autres fonctionnalités. C’est ainsi que sont apparues d’autres bibliothèques standard comme Core, ou Batteries. Chacune des bibliothèques standard ont leurs particularité, l’important étant qu’OCaml vous laisse le choix.

En ce qui concerne le langage en lui-même, il faut savoir qu’OCaml est un langage fonctionnel dit impur. Pourquoi ? Parce que le langage offre également des concepts de programmation impérative, et même orientés objet. Ce qui signifie qu’au sein d’un même programme, vous pouvez tirer parti des avantages des trois paradigmes à la fois.

Des fonctionnalités hors du commun

Je vais terminer sur ce point, parce que c’est celui qui, en tant que passionné d’informatique, m’a le plus bluffé. Au fur et à mesure que je découvrais OCaml, je tombais à droite à gauche sur des fonctionnalités qui m’ont ébloui tellement elles sont puissantes. En voici une petite compilation.

Les variantes

Une variante est un type de données qui permet à une valeur d’avoir différents types. Prenons l’exemple de JSON. Avec une variante OCaml, voici comment décrire la grammaire d’un objet JSON:

type json =
  | Object of (string * json) list
  | Bool of bool
  | Float of float
  | Int of int
  | List of json list
  | Null
  | String of string

Un peu à la manière d’un type union en C, la valeur d’une variante correspond à l’un des constructeurs donnés avec un argument d’un type donné. Là où ça devient vraiment intéressant, c’est que les variantes peuvent être récursives ! Dans l’exemple ci-dessus, un Object JSON est en fait une liste de JSON associés à un nom. Les possibilités de ces types sont ahurissants, et encore, je vous ai pas parlé des variantes polymorphiques.

Le pattern matching

Le pattern matching (ou reconnaissance de motif en français) est une technique qui permet d’analyser la structure d’une donnée, comme une liste ou une variante. Voici un bout de code qui calcule la somme d’une liste d’entiers :

let rec sum = function
  | h::t -> h + sum t (* Cas récursif *)
  | [] -> 0 (* Cas initial *)

Ici, les deux expressions correspondent à deux structures possibles pour une liste :

  • h::t correspond à une liste quelconque non-vide : h représente la tête de la liste et t le reste ;
  • [] correspond à une liste vide.

Là où OCaml devient incroyable, c’est qu’il est capable de vérifier qu’un pattern couvre tous les cas possibles. Par exemple, dans l’exemple ci-dessus, ci on oublie de préciser le cas initial, voici ce que le compilateur dit :

Warning 8: this pattern-matching is not exhaustive.
Here is an example of a value that is not matched:
[]

Comme je le disais plus tôt, sécurité.

Les objets immédiats

OCaml a à sa disposition toutes les fonctionnalités d’un langage orienté objet, avec en plus une toute petite chose qui transcende les autres langages orientés objet : les objets immédiats.

Dans n’importe quel langage OO, un objet est par définition une instance de classe. Le type d’un objet correspond donc à la classe à partir de laquelle il a été construit (sauf polymorphisme, mais je m’égare). En OCaml, on peut parfaitement construire un objet sans utiliser de classe. Comment ? En réalité, le système de typage d’OCaml est incroyablement complexe, et, pour lui, le type d’un objet est défini par la signature de ses méthodes. C’est à la fois parfaitement logique et incroyablement puissant, tout en respectant la rigueur du typage. Voici, par exemple, un objet immédiat désignant un rectangle :

let rectangle = object (self)
  val x1 = 1
  val y1 = 1
  val x2 = 3
  val y2 = 5
  
  method length = max (abs (x2-x1)) (abs (y2-y1))
  method width = min (abs (x2-x1)) (abs (y2-y1))
  method area = self#length * self#width
  method inside x y =
    x >= min x1 x2 &&
    x <= max x1 x2 &&  y >= min y1 y2 &&
    y <= max y1 y2
end

Le type de rectangle est défini comme suit

< area : int; inside : int -> int -> bool; length : int; width : int >

et l’objet rectangle peut-être utilisé à n’importe quel endroit où ces méthodes sont suffisantes. Et ça, encore une fois, c’est beau.

Le chercheur de tare en trouvera même au paradis

Aussi incroyable et bien pensé qu’il est, OCaml a malgré tout du mal à percer dans le monde de l’informatique. Facebook l’utilise en interne pour des outils d’analyse de code, quelques sociétés s’en servent de manière plus générale, mais dans l’ensemble, je pense qu’OCaml devrait être plus populaire que ça. Quelques pistes de réflexion ici.


Voilà qui conclut ce billet, le premier de 2016. Oui, on est en décembre, et alors ?

Je sais que je dis ça à chaque article, mais j’ai vraiment envie d’écrire plus souvent sur ce blog. Je dois bien avouer que le temps manque, et les idées aussi. Mais bon, un jour peut-être aurai-je le courage de mettre en place un planning de publication régulier.

Une pensée sur “OCaml et moi, une grande histoire d’amour”

  1. Il manque un comparatif avec d’autres langages fonctionnels (Haskell), mais aussi d’autres langages émergents (Rust, Go), pour comprendre pourquoi ils évoluent plus vite qu’OCaml. Ma théorie est que les cas d’utilisations d’OCaml est sur un marché qui évolue très lentement (la sécurité). Mais peut être ça pourrait être l’objet d’un prochain article ? 🙂

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *