Je pense sincèrement que n’importe quel langage demande un bagage préalable si tu n’as pas un cours qui te prend par la main pour l’apprendre (ce que le book de Rust n’est pas, on est bien d’accord). C’est bien pour ça que le SdZ avait été créé à l’époque. Et quel que soit le langage, il n’y a pas grand chose à attendre des créateurs du langage : par exemple, ce n’est pas Peyton-Jones qui a écrit Learn You a Haskell…
Maintenant, il est évident qu’avoir un bagage en programmation fonctionnelle aide pour apprendre Rust. Mais je ne pense pas que la programmation fonctionnelle en soi rende l’apprentissage du langage plus facile qu’un bagage en POO. Je m’explique.
Rust est très loin d’être un langage fonctionnel. Même s’il en utilise des bouts, comme le type Option
ou le filtrage par motifs, sur de nombreux aspects, les réflexes de la programmation fonctionnelle n’y sont pas applicables, entre autres pour les raisons suivantes.
- Il n’y a pas de HKT et au rythme où ça avance, je doute qu’il y en ait un jour.
- Il n’existe pas d’interface unique permettant de passer des fonctions en argument ou en valeur de retour (y’en a quatre différentes, quand même…).
- Ces deux points transforment en calvaire la création de toute monade digne de ce nom.
- Le système de fonctions constantes est absolument moisi, même s’il y a plus d’espoir de le voir devenir quelque chose de correct que pour les HKT.
- La programmation idiomatique utilise généralement des boucles sur des itérateurs plutôt que des
map
ou de la récursion.
Tout ça pour dire que quelqu’un qui ne connaîtrait que la programmation fonctionnelle s’en prendrait plein la gueule avec le système d’objets, aussi rudimentaire soit-il, l’absence de tout un tas de trucs pratiques, les itérateurs, etc. Toutes choses qui ne poseront aucune difficulté à qui vient du monde OO.
Ce qu’il se passe, c’est que sauf rares exceptions, les gens qui ont un bagage en programmation fonctionnelle ont aussi un bagage dans un paradigme plus courant.
Les autres critiques que je faisais étaient que je trouve bizarre d'être si rigide quand on fait un pop et aussi laxiste que les autres langages quand on récupère un élément directement (avec les crochets).
Je ne vois pas ce qu’il y a de si bizarre, en fait. Il n’y a pas de types dépendants en Rust : le type donne juste une indication de type et ne contient aucune information sur les données effectivement contenues. Comme ce n’est sans doute pas très clair, prenons un exemple.
Le type Vec<T>
se contente de dire « ceci est une collection qui peut contenir des objets de type T ». Et les fonctions d’accès, que ce soit []
ou get
prennent en entrée « une collection qui peut contenir des objets de type T ».
Si on avait des types dépendants, on pourrait définir un truc comme Vec<T, N ∈ ℕ>
, soit « une collection qui prend un nombre entier positif ou nul d’objets de type T ». Et un vec![1, 2, 19]
aurait pour type Vec<i64, 3>
. Et surtout, la fonction pop
aurait pour type Vec<T, N ∈ ℕ*> -> (Vec<T, N-1>, T)
. Et il deviendrait alors impossible de passer un vecteur vide à la fonction.
Sauf erreur de ma part, ce genre de choses est possible en Idris, par exemple. Mais on voit bien que si on combine ça avec de la mutabilité, ça commence à devenir vraiment sale…
Du coup, dans la mesure où le système de typage ne permet pas en soi d’interdire de passer à la fonction un objet du bon type mais contenant les mauvaises données, et qu’il n’y a aucune intention de le faire, eh ben on laisse au programmeur sa responsabilité. Tu as ainsi un accesseur rapide mais risqué []
et un accesseur plus lent mais sans risque get
.
Ainsi que les messages d'erreur du compilateur complètement illisibles à l'époque (liée à la jeunesse du langage) – toi tu les dis géniaux, donc j'imagine qu'ils ont fait de gros progrès.
Vu ce que tu décris dans ton message d’origine, les messages d’erreurs sont toujours les mêmes plus ou moins. Là où on n’est pas d’accord, c’est quand tu dis qu’ils sont illisibles. Le message d’erreur que tu as rencontré pointait exactement le problème rencontré, dès la première ligne, et avec une formulation qui ne laissait aucune place au doute :
Le trait
Display
n’est pas implémenté pour le typeOption
.
Je conçois qu’étant nouveau, on puisse ne pas connaître le trait Display
, voire le type Option
(encore que, comme le pointait Eusèbe, si tu utilises une fonction qui renvoie un type Option
sans te renseigner sur ce que c’est, c’est toi le fautif…).
Mais alors, tu cherches dans la doc ce que c’est que ce Display
. Dont l’explication n’est pas très claire, on est d’accord, mais qui redirige immédiatement vers cette page où tout est expliqué en détail et, a minima, tu comprendras qu’il y a un problème avec l’affichage.
Maintenant, on ne peut pas vraiment faire mieux comme message d’erreur.
- La fonction
Vec::pop()
renvoie unOption
, c’est prévu pour et parfaitement légal. - Rien ne t’oblige à déstructurer ton
Option
, tu peux parfaitement continuer à travailler directement dessus, il n’y a donc aucune raison que le compilateur râle à ce sujet. - Il est parfaitement légal de passer n’importe quelle variable à la macro
println!()
, ne serait-ce que parce que les macros ne vérifient pas les types (même si on l’utilise comme une fonction, il faut voir ça plus comme une macro C qui va te remplacer ça par un bloc dégueulasse chargé du formatage et de l’affichage). - La fonction chargée de réaliser le formatage dans le cas général n’existe pas pour
Option
→ erreur, et message lié.