💾 Archived View for heyplzlookat.me › articles › critique-de-la-raison-pure.gmi captured on 2023-11-04 at 11:31:04. Gemini links have been rewritten to link to archived content
⬅️ Previous capture (2023-09-08)
-=-=-=-=-=-=-
En ce moment, c'est la mode de donner son avis sur OCaml. Du monde s'y essaie et critique forcément des points plus ou moins pertinents. Je vais tenter de discuter et répondre aux critiques adressées au langage dans ce blog post :
https://borretti.me/article/two-years-ocaml
C'est un avis que je trouve intéressant étant donné que l'auteur indique avoir, tout comme moi, deux ans d'expérience avec OCaml mais aussi et surtout car l'auteur ne parle pas français et ne peut donc pas répondre à mes tacles (dsl).
Je vais d'abord évoquer les critiques que je juge mineures, puis discuter de celles visant le système de module. Pour chaque point mentionné, je posterai le lien de la section de l'article correspondante et la commenterai.
https://borretti.me/article/two-years-ocaml#semicolons
let foo () = if cond then do_something (); do_something () else do_something_else ()
Le fait que ce bout de code ne marche pas comme escompté est lié à la possibilité d'écrire un if de type unit sans branche else :
if cond then print_endline "bar"; do_something ()
Cette forme génère donc une ambiguïté avec un if else complet classique si l'expression qui suit le if est un enchaînement de _statement_ qui n'est pas entouré de parenthèse.
Ça ne me choque pas d'avoir ce sucre syntaxique pour cette forme, très pratique quand on travaille avec des tableaux, dans un langage en partie impératif comme OCaml. Utiliser les délimiteurs begin/end dans la branche du if me paraît être le bon compromis à un `let _ = ... in ...` :
if cond then begin do_something (); do_something () end else do_something_else ()
https://borretti.me/article/two-years-ocaml#inconsistency
La distinction syntaxique expression/type ne relève pas d'une incohérence pour moi mais plutôt d'un choix qui permet de distinguer au premier coup d'œil un type ou une expression (ce qui est particulièrement utile quand on utilise des modules). En admettant cette symétrie (val/let, sig/struct, etc), il n'y donc pas vraiment d'incohérence à ce que je sache.
https://borretti.me/article/two-years-ocaml#modules
Le point clef de l'article est la critique du système de module sur lequel l'auteur fait pour moi fausse route.
Lorsque l'on compare strictement les foncteurs et les type classes, ces dernières semblent bien plus pratiques à utiliser sur le papier. En effet, dans des cas simples, les type classes offrent des solutions élégantes et laisse le compilateur s'occuper des boilerplates. Certes, l'absence de polymorphisme ad-hoc dans OCaml est regrettable (https://arxiv.org/pdf/1512.01895.pdf bientôt, nous espérons), mais je pense qu'il faut plutôt appréhender les foncteurs comme un outil de métaprogrammation pour faire de la génération de code plutôt qu'une manière de faire du polymorphisme stricto sensu.
Par exemple, Mirage OS fait particulièrement bien usage des signatures de module pour s'abstraire du runtime en permettant de faire des logiciels « platform-agnostic ». Et cela en imposant le fait de devoir paramétriser un foncteur contenant le programme principal par des modules encapsulant des fonctions qui effectuent des effets de bord, puis en les remplaçant à la compilation par des implémentations concrètes adaptées au système visé.
module Main (Pclock : Mirage_clock.PCLOCK) (Stack : Tcpip.Stack.V4V6) = struct ... end
Extrait de code typique d'un unikernel conçu avec Mirage OS
De cette façon, il est plus simple de construire un logiciel en empilant des modules brique par brique qu'en faisant appel aux type classes d'Haskell.
https://borretti.me/article/two-years-ocaml#equality
Je suis d'accord avec l'auteur, même s'il faut noter que la question de l'égalité reste cohérente si l'on se restreint à la bibliothèque standard d'OCaml. En effet, même si elle ne fait aucune mention explicite de la signature suivante :
module type COMPARABLE = sig type t val comparable : t -> t -> int end
La plupart des modules l'implémentent implicitement en définissant un type `t` et une fonction de comparaison spécialisée. De plus, les quelques foncteurs que la stdlib fournis (Map et Set) utilisent une signature équivalente sous un autre nom (`OrderedType`) et demeurent donc compatibles.
De toute façon, les bibliothèques standards alternatives (containers, core) tirent pleinement parti du système de module en implémentant des signatures communes.
https://borretti.me/article/two-years-ocaml#ppx
L'instanciation des foncteurs se fait au runtime et il est donc impossible de profiter des capacités des PPX dans ce cas mais je pense que cette critique est issue de la frustration de l'auteur qui n'a pas pris le problème dans le bon sens (mais qui a finalement trouvé la solution à son problème et l'a indiqué dans sa réponse dans le sujet Stackoverflow).
À bientôt pour un prochain article où j'arrêterai de critiquer les autres et donnerai mon propre avis désastreux sur OCaml.
Pas encore de commentaires