• [^] # Re: Performance

    Posté par . En réponse au journal Moi, expert C++, j'abandonne le C++. Évalué à 4. Dernière modification le 10 juin 2019 à 13:14.

    Je sais bien que Go fait du typage statique (même s'il fait fait du typage dynamique pour la généricité avec l'interface {}). Ce que je voulais dire c'est que le problème que tu cherchais à illustrer ne relève pas de la distinction typage dynamique vs. typage statique, mais d'une limitation du paradigme objet et de la façon dont il gère le polymorphisme ad-hoc. Go n'est pas orienté objet, tout comme Haskell ou Rust ne le sont pas. En Haskell ton code passera par des type classes :

    class User a where
     greetings :: a -> String
    data Plouf = Plouf { FirstName :: String, LastName :: String, Addr :: String }
    instance User Plouf where
     grettings user = ...

    En Rust, ce sera par des traits, ce qui n'est pas de l'orienté objet.

    Pour illustrer la distinction entre l'approche objet et celle de Go, Haskell et Rust, faisons cela en OCaml.

    Selon le paradigme objet, on aurait une méthode greetings sur notre objet

    class fst_name last_name addr = object
     val fst_name = fst_name
     val last_name = last_name
     val addr = addr
     method greetings () = Printf.sprintf "Dear %s %s" fst_name last_name
    end

    et la fonction foo appellerait cette méthode sur notre objet

    let foo o = print_endline (o#greetings ())
    let u = new plouf "Matt" "Aimonetti" "chez moi" in foo u;;
    (* le retour *)
    Dear Matt Aimonetti

    Dans l'approche objet, les opérations sur le triplet de string ne sont pas dissociables du types : c'est un tout. Ce que tu exprimais dans ton commentaire ainsi :

    Le type Plouf n'a aucun rapport avec l'interface User. Ça permet d'écrire après coup des fonctions qui définissent des interfaces décrivant le contrat que doivent remplir leur arguments sans impact sur les types créé ailleurs.

    Dans l'approche objet, le dictionnaire de méthodes (ici User) et le type sur lequel elles opèrent (ici Plouf) sont indissociables. Dans l'approche de Go, Haskell ou Rust le dictionnaire de méthode et le type sont dissociés. C'est ce que j'ai cherché à expliquer dans ma réponse précédente, et c'est aussi la raison pour laquelle en OCaml on passera par des modules et non des objets pour modéliser une telle problématique.

    (* la version OCaml de la type classe Haskell *)
    module type User = sig
     type t
     val greetings : t -> string
    end
    module Plouf = struct
     type t = {
     first_name : string;
     last_name : string;
     addr : string
     }
     let greetings {first_name; last_name; _} =
     Printf.sprintf "Dear %s %s" first_name last_name
    end
    let foo (type a) (module M : User with type t = a) x = M.greetings x

    La différence ici, avec les trois autres langages, est que l'on peut définir plus d'un dictionnaire pour un même type : il doit donc être passer explicitement à la fonction foo. Là où, dans les autres langages, le dictionnaire étant unique pour un type donné, il est déterminé univoquement à partir du type de la variable x.

    Pour bien illustrer la différence avec le paradigme objet, c'est cela le type d'un objet :

    type 'a user_object = 'a * (module Meth : User with type t = 'a)

    c'est la donnée conjointe d'une valeur de type 'a (les attributs de l'instance) et des méthodes sur ces attributs, conjonction que l'on ne peut séparer en ses composantes au niveau du système de type.

    Ceci étant, bien que je trouve ce paradigme plus intelligent que celui du paradigme objet, la façon dont il existe en Go reste très limitée : tu ne peux pas surcharger des opérateurs binaires avec (addition, comparaison, test d'égalité...).

    Sapere aude ! Aie le courage de te servir de ton propre entendement. Voilà la devise des Lumières.