• # Mettre la complexité dans le typage

    Posté par (site web personnel) . En réponse au journal Typage statique versus typage dynamique. Évalué à 10.

    Je plussoie la plupart des affirmations du journal et des blogs cités.

    Pour faire du fonctionnel au quotidien, j'ai fini par comprendre qu'outre quelques bugs qui disparaissent du fait de l'interdiction des valeurs nulles, et autres erreurs de type, on peut très vite se retrouver avec beaucoup d'erreurs si on utilise assez mal( ou trop peu) le système de type des langages fonctionnels.

    Autrement dit, il faut toujours chercher à coder la difficulté dans le typage et non dans l'algorithme.
    Un exemple classique est la sur utilisation des chaines de caractères, qu'on va utiliser abusivement lorsqu'on échange avec la base de donnée. L'idéal est de typer au maximum pour profiter des capacité du compilateur de débusquer les erreurs qui se planquent dans le traitement.

    Les langages fonctionnels apportent en plus le typage somme, qui est un espèce d'Enum de java/C/… boosté aux stéroids, avec la capacité de pattern matcher dessus, tout en profitant de la capacité du compilateur de vérifier l'exhaustivité du switch case.

    Un exemple, en java

    public enum connection_state {
     Connecting , Connected , Disconnected 
    }
    public class connection_info { 
     connection_state state ; 
     inet_addr server; 
     time last_ping_time; 
     int last_ping_id; 
     string session_id; 
     time when_initiated; 
     time when_disconnected; 
    }
    
    

    Pour les camelistes

    type connection_state = 
    | Connecting 
    | Connected 
    | Disconnected 
    type connection_info = { 
     state: connection_state; 
     server: inet_addr; 
     last_ping_time: time option; 
     last_ping_id: int option; 
     session_id: string option; 
     when_initiated: time option; 
     when_disconnected: time option; 
    }
    
    

    Premier problème, en java, un certain nombre de champ peuvent être nulles. En Ocaml, avec le option, on a la garantie de relever les cas nuls à la compilation.

    La structure en Java est merdique car on doit maintenir des champs à Null ou à une valeur stupide car tous les champs ne servent pas : on se fiche du session_id lors qu'on se connecte ou qu'on est déconnecté.
    On a ainsi une structure à "champ libre", c'est à dire que c'est à l'algo de vérifier la cohérence des données .Le compilateur ne peut rien faire là dessus.

    Grâce au type somme disponibles dans les principaux langages fonctionnels (OCaml, Haskell, Scala), on va pouvoir disposer d'une structure de donnée logique, et plus facilement vérifiable :

    type connecting = { when_initiated: time; } 
    type connected = { last_ping : (time * int) option; 
     session_id: string; } 
    type disconnected = { when_disconnected: time; } 
    type connection_state = 
    | Connecting of connecting 
    | Connected of connected 
    | Disconnected of disconnected 
    type connection_info = { 
     state: connection_state; 
     server: inet_addr; 
    }
    
    
    1. L'algorithme travaille sur des données représentant réellement l'information telle qu'on la conçoit dans notre cerveau.
    2. La vérification de l'exhaustivité du pattern matching nous garantit qu'on traite tous les cas
    3. Les types ajoutés d'option nous garantissent le traitement des valeurs nulles.*

    Bref, certes oui, le statiquement typé permet de trouver quelques erreurs, mais ne remplace pas les tests unitaires, mais ce serait intéressant de refaire l'expérience, en restructurant les codes qu'il a étudié en véritable typage fonctionnel pour voir si le compilateur ne détecte pas de bugs intéressants…

    *
    Comment ça marche ?
    On définit une valeur d'une structure comme étant string option :
    type mastructure = { champ : string option }
    À partir de là mastructure.champ doit valoir, soit Some "Contenu de la chaine", soit None
    Si vous traitez qq part mastructure.champ, vous devez la pattern matcher :

    match mastructure.champ with
    | Some s -> code à exécuter avec s == "Contenu de la chaine"... 
    | None -> On doit traiter l'erreur sinon le compilateur gueule
    
    

    « Il n’y a pas de choix démocratiques contre les Traités européens » - Jean-Claude Junker