web-dev-qa-db-fra.com

Quel est le gain de productivité supposé du typage dynamique?

J'ai souvent entendu l'affirmation selon laquelle les langues typées dynamiquement sont plus productives que les langues typées statiquement. Quelles sont les raisons de cette réclamation? N'est-ce pas simplement un outillage avec des concepts modernes comme la convention sur la configuration, l'utilisation de la programmation fonctionnelle, des modèles de programmation avancés et l'utilisation d'abstractions cohérentes - qui pourraient tous être également utilisés dans des langages typés statiquement? Certes, il y a moins d'encombrement car les déclarations de type (par exemple en Java) souvent redondantes ne sont pas nécessaires, mais vous pouvez également omettre la plupart des déclarations de type dans les langages typés statiquement qui utilisent l'inférence de type, sans perdre les autres avantages de la frappe statique. Et tout cela est également disponible pour les langages modernes typés statiquement comme Scala également.

Alors: que dire de la productivité avec un typage dynamique qui est vraiment un avantage du modèle de type lui-même?

Clarification: je suis plus intéressé par les projets de grande/moyenne taille que par les hacks rapides. :-)

86
Hans-Peter Störr

En fait, je pense que c'est un appel assez proche. Le typage dynamique et le typage statique ont leurs avantages.

Raisons pour lesquelles la frappe dynamique est plus productive:

  • C'est plus concis - Beaucoup de code passe-partout étranger peut être supprimé si tout est typé dynamiquement - déclarations de type, logique de transtypage, etc. Toutes choses étant égales par ailleurs, un code plus court est légèrement plus rapide à écrire, mais plus important encore, il peut être plus rapide à lire et à maintenir (car vous n'avez pas besoin de parcourir plusieurs pages de code pour avoir une idée de ce qui se passe)
  • Des techniques plus faciles à "pirater" telles que la frappe de canard et la correction de singe peuvent vous donner des résultats très rapidement (bien que cela puisse vous embrouiller plus tard ...)
  • Plus interactif - le typage dynamique est sans doute plus adapté à une programmation interactive de type REPL pour le prototypage rapide, le débogage en temps réel des instances de programme en cours d'exécution ou même le codage en direct .
  • Les cas de test peuvent détecter les erreurs d'exécution - en supposant que vous utilisez TDD ou à tout le moins une bonne suite de tests, cela devrait détecter tout problème de frappe dans votre code.
  • Meilleur polymorphisme - les langages dynamiques sont potentiellement plus susceptibles d'encourager la création de fonctions polymorphes et d'abstractions, ce qui peut augmenter la productivité et la réutilisation du code. Clojure, par exemple, fait un grand usage du polymorphisme dynamique dans ses nombreux abstractions .
  • Prototypes - basés sur des prototypes les modèles de données/objets sont à mon avis plus puissants et flexibles que les héritages d'héritage typés statiquement. Les langages dynamiques sont plus susceptibles d'autoriser ou d'encourager une approche basée sur un prototype, Javascript en étant un excellent exemple.

Raisons pour lesquelles le typage statique est plus productif:

  • Meilleure conception - être obligé de penser à l'avance aux types de valeurs dans votre logiciel peut vous pousser vers des solutions plus propres et plus logiques. (Je dis peut - il est toujours possible de concevoir un code vraiment mauvais ...)
  • Meilleure vérification du temps de compilation - le typage statique peut permettre de détecter plus d'erreurs au moment de la compilation. C'est un énorme avantage, et c'est sans doute la meilleure chose à propos des langages typés de manière globale.
  • Saisie semi-automatique - la saisie statique peut également donner plus d'informations au IDE afin que la saisie automatique du code ou de la documentation la recherche est plus efficace.
  • Décourage les hacks - vous devez conserver la discipline de type dans votre code, ce qui est probablement un avantage pour la maintenabilité à long terme.
  • Inférence de type - dans certaines langues (par exemple Scala), cela peut vous apporter de nombreux avantages de concision des langages dynamiques tout en maintenant la discipline de type.

En moyenne, ma conclusion (après de nombreuses années d'expérience des deux côtés de la clôture) est que le typage dynamique peut être plus productif à court terme, mais il devient finalement difficile à maintenir à moins d'avoir de très bonnes suites de tests et une discipline de test.

D'un autre côté, je préfère en général les approches typées statiquement, car je pense que les avantages de la correction et la prise en charge des outils vous offrent une meilleure productivité à long terme.

100
mikera

Avec les langages dynamiques, vous pouvez écrire du code merdique plus rapidement que lorsque vous utilisez un langage tapé.

Une fois que vous avez rapidement créé votre énorme tas de choses dynamiques, vous pouvez passer en toute sécurité à un autre projet sans avoir à vous soucier de la maintenance à long terme.

C'est un gain de productivité :)

Je plaisante, mais après avoir été impliqué dans un projet utilisant un `` langage dynamique '', j'ai été effrayé par la quantité de tests, de documentations et de conventions inutiles auxquels vous devez faire face si vous voulez avoir un produit fonctionnel.
Et avec la joie de nombreuses erreurs d'exécution qui auraient pu être détectées lors de la compilation.
Oh, j'ai aussi oublié de me plaindre de tous ces hacks et vaudous que la méta-programmation vous permet d'introduire dans votre code!

Ainsi, le gain de productivité pourrait être un mythe pour un projet moyen/grand au cours de sa durée de vie.

56
Guillaume

Il existe également une vision théorique de ce problème: un système de type statique est essentiellement un prouveur de théorèmes spécialisé qui n'accepte le programme que lorsqu'il peut en prouver l'exactitude. Tous les systèmes de type statique rejettent certains programmes valides car aucun système de type statique décidable n'est suffisamment puissant pour prouver tous les programmes de type correct possibles.

On pourrait faire valoir que les programmes qui ne sont pas prouvables par un vérificateur de typage statique sont des hacks et/ou un mauvais style, mais si vous avez déjà un programme valide et que le vérificateur de typage ne l'accepte pas, cela nuit certainement à votre productivité à court terme.

Dans certains cas, vous remarquerez peut-être que le vérificateur de type se met en travers avec des conteneurs génériques et une co-/contravariance dans les arguments et les types de retour.

16
Patrick

Un avantage que j'ai trouvé avec la plupart des langages dynamiques est qu'ils facilitent l'écriture de code plus générique. Il est beaucoup plus facile d'écrire à un niveau d'abstraction plus élevé lorsque vous n'avez pas à combattre le système de type pour le faire.

Vous n'avez pas à y penser autant - écrire du code qui fait quelque chose de non trivial avec n'importe quel objet dans Java = est difficile et nécessite probablement une réflexion qui est typiquement dynamiquement typée; avec quelque chose comme JavaScript, écrire une fonction qui fait quelque chose d'intéressant pour tous les objets est une seconde nature. Un exemple parfait serait une fonction que j'ai récemment écrite qui prend un objet et remplace tout ses méthodes avec celles qui font la même chose mais déclenchent également un événement. Je ne sais pas comment aborder quelque chose comme ça en Java. Cependant, je ne sais pas combien cela est dû aux systèmes de type et combien en raison d'autres différences linguistiques.

Cependant, j'ai récemment commencé à utiliser Haskell. Haskell me permet d'écrire du code générique abstrait aussi facilement que n'importe quel langage typé dynamiquement que j'ai utilisé. Mon exemple Java/JavaScript ci-dessus n'a aucun sens dans Haskell car il n'a pas d'objets, de méthodes, d'événements ou même beaucoup de mutation, mais d'autres sortes de génériques le code est vraiment facile à écrire.

En fait, Haskell peut écrire du code générique que les langages typés dynamiquement ne peuvent pas; un exemple parfait est la fonction read qui est fondamentalement l'opposé de toString. Vous pouvez obtenir un Int ou un Double ou tout autre type que vous voulez (tant qu'il est dans une certaine classe de type). Vous pouvez même avoir des constantes polymorphes , donc maxBound peut être le maximum Int, Double, Char... etc., tout dépend de quel type il est censé être.

Ma théorie est maintenant que le gain de productivité en utilisant un langage dynamique est toujours en comparaison avec des langages comme Java avec des systèmes de type moins capables, plus verbeux et moins flexibles.

Cependant, même le système de type de Haskell a des problèmes ennuyeux que vous n'auriez pas dans un langage typé dynamiquement. Le plus gros problème me dérange, c'est la façon dont les chiffres sont traités; par exemple, vous devez jouer avec le système de types pour utiliser length (d'une liste) comme double, ce que vous n'auriez aucun problème sans un système de types. Une autre chose ennuyeuse que j'ai rencontrée est de travailler avec Word8 (un type int non signé) et des fonctions qui attendent Int.

Ainsi, en fin de compte, l'absence de système de type facilite l'écriture de code générique sans trop réfléchir et évite également les pièges ennuyeux des systèmes de type. Vous n'avez jamais à combattre le système de type dans un langage dynamique, mais vous ne pouvez pas non plus vous y fier.

15
Tikhon Jelvis

Q: J'ai souvent entendu l'affirmation selon laquelle les langues typées dynamiquement sont plus productives que les langues typées statiquement. Quelles sont les raisons de cette réclamation? "

Cela a des raisons historiques. Si vous remontez quelques décennies en arrière, les langages dynamiques étaient incontestablement beaucoup plus productifs que les langages statiques (tout en étant également beaucoup plus lents). Perl est clairement beaucoup plus productif que C si vous connaissez les deux et que la tâche à accomplir le permet. Mais au fil du temps, les langues se sont beaucoup empruntées les unes aux autres, et les nouvelles langues réduisent l'écart (en termes de productivité et de performances).

Voici quelques points à considérer:

Garbage collection: Garbage collection est un énorme accroissement de la productivité. Je crois que Java a été le premier langage statique traditionnel avec GC. Avant cela, statique signifiait essentiellement la gestion manuelle de la mémoire. (Remarque: ici et ci-dessous, je ne considère que les langages traditionnels. Beaucoup d'expérimental) et il existe des langages de niche qui fourniront des contre-exemples à tout point que je soulèverai.)

Sécurité de la mémoire: C'est une amélioration de la productivité que vous n'avez pas à vous soucier de vous tirer une balle dans le pied. Avant les langages statiques "gérés" comme Java, statique signifiait généralement un accès direct à la mémoire. Le débogage fait également partie de la productivité, et un accès à la mémoire non sécurisé peut conduire à des bugs vraiment obscurs.

Systèmes de types encombrants. Avant l'introduction des types paramétrés (comme les modèles ou les génériques) dans les langages statiques, les limitations des systèmes de types statiques étaient souvent un fardeau. Par exemple, en Java vous avez dû explicitement abattre chaque fois que vous avez choisi un élément d'une collection. Vous avez donc obtenu la surcharge syntaxique d'une distribution et aucune sécurité de type. Compte tenu de l'omniprésence des collections en programmation, c'était un inconvénient majeur.
Devant déclarer le type de tout, c'est beaucoup de frappe redondante, mais avec l'inférence de type moderne, cela peut être considérablement réduit.

Grande bibliothèque standard. Python était célèbre comme "piles incluses" en raison de la grande bibliothèque standard. Ceci en comparaison avec C qui a une bibliothèque standard très minimaliste. Mais avec des plateformes comme Java et .net, une vaste bibliothèque standard devient standard, et des langages plus récents comme Scala et F # héritent de cela "gratuitement").

Structures de données de première classe. Les langages dynamiques comme Perl et Python ont des structures de données de première classe intégrées comme des listes et des cartes avec des raccourcis syntaxiques pratiques pour les opérations courantes. Par rapport à cela, C n'a pas de collections intégrées à l'exception des tableaux de taille fixe.

Fermetures et syntaxe lambda - les langages dynamiques l'ont généralement depuis le début, mais les langages statiques l'ont adopté, plus récemment Java.

REPL la possibilité de tester rapidement des extraits de code de manière interactive est une énorme bénédiction. Mais bien que les outils IDE, comme la fenêtre "immédiate" dans Visual Studio, les langages statiques peuvent émuler cela dans une certaine mesure.

Outillage avancé - en plus des points ci-dessus où les langages statiques se rapprochent de la commodité des langages dynamiques, les éditeurs modernes profitent de l'analyse statique d'une manière que les langages dynamiques ont du mal à faire correspondre. Par exemple, les éditeurs peuvent fournir des refactorisations automatiques sûres, ce qui est strictement impossible dans un langage dynamique.

Conclusion: Historiquement, c'était vrai, mais aujourd'hui, la réponse est moins claire.


Q: Alors: que dire de la productivité avec le typage dynamique qui est vraiment un avantage du modèle de type lui-même?

Il est quelque peu difficile de séparer le modèle de typage dynamique des langages dynamiques, mais à titre d'exemple, C # a adopté des fonctionnalités plus dynamiques au fil du temps, même si son cœur est un langage statique. C'est vraiment une preuve de l'avantage du modèle de type dynamique. Exemples:

Réflexion La réflexion est fondamentalement une fonction de frappe dynamique. Vous inspectez les types d'objet au moment de l'évaluation plutôt qu'à la compilation. Quand il a été introduit, il était un peu mal vu, mais en C #, l'utilisation de la réflexion devient de plus en plus omniprésente, par exemple ASP.Net MVC utilise fortement la réflexion.

Attributs Les attributs sont un exemple de typage dynamique. Vous pouvez ajouter des attributs arbitraires à une classe au moment de la compilation, puis inspecter au moment de l'exécution (par réflexion) et manipuler des objets en fonction de celle-ci. Quelque chose comme MEP est essentiellement un cadre d'extension basé sur un modèle de type dynamique.

Linq to SQL, EF mv. Les différents transformateurs Linq inspectent les requêtes en tant qu'objets d'exécution et génèrent sql à la volée. Il n'est pas plus dynamique que l'inspection du code lors de l'exécution. CodeDom est l'autre côté de la médaille, où le code peut être généré lors de l'exécution

Roslyn Roslyn implémente fondamentalement eval, qui était autrefois considérée comme la caractéristique déterminante d'un langage vraiment dynamique.

Dynamic Le type dynamic- est la fonctionnalité la plus explicitement dynamique en C #, et est annoncée pour rendre l'interaction avec des objets et des langages externes plus simple et plus productive. Mais il est également utilisé dans Asp.net MVC pour plus de commodité.

L'avantage de toutes les fonctionnalités ci-dessus montre que le modèle dynamique présente des avantages certains même dans un langage statique avec des types paramétrés, des types structurels et une inférence de types.

10
JacquesB

L'ensemble de toutes les fonctionnalités du langage moderne est si grand que le typage statique vs dynamique seul n'a pas beaucoup de poids.

La règle est la suivante: meilleures sont les fonctionnalités de votre langue, plus court est votre code. C'est assez simple. Java montre comment la saisie statique peut mal tourner, ce qui donne à ses adversaires beaucoup à se nourrir. Les fonctionnalités de langage mal conçues ont généralement un coût, et la saisie statique dans Java est d'abord une fonctionnalité obligatoire (sinon la plupart des gens ne l'utiliseraient probablement même pas) et deuxièmement mal exécutée.
C'est pourquoi, en comparaison, la plupart des langues dynamiques brillent, même si je dirais que PHP ne rend pas vraiment votre vie meilleure dans le grand total (au moins jusqu'à récemment), en raison de nombreuses autres bizarreries sans rapport avec les systèmes de type.

D'un autre côté, vous avez beaucoup de langues avec des systèmes de type expressifs qui ne vous gênent pas et qui ne sont même pas obligatoires. Et certains d'entre eux permettent même d'incorporer du code non typé, chaque fois que vous devez échapper au système de type.

Personnellement, j'utilise haXe, qui est un langage avec inférence de type, sous-typage nominal et structurel, code facultatif non typé, types de fonctions de première classe, types de données algébriques et macros lexicales (pas tout à fait matures mais extrêmement puissantes), tout en évitant la syntaxe arcanique. Après avoir utilisé haXe pendant environ 3 ans maintenant, je suis arrivé à une conclusion simple:

La programmation devient beaucoup plus facile, lorsque votre langue ne vous enferme pas dans des choix religieux sur les paradigmes mais essaie simplement d'être un bon outil. Il existe un certain nombre de langues statiques et dynamiques et mixtes langues, qui réussissent à cela. Certains d'entre eux sont faciles à apprendre, les plus difficiles à maîtriser.
Leur puissance vient de la façon dont leurs caractéristiques individuelles peuvent être composées pour créer facilement des solutions simples à des problèmes complexes. Cela exclut une certaine orthogonalité qui ne peut être obtenue que par un équilibre délicat d'inclusion ou d'omission de toutes les fonctionnalités linguistiques explorées jusqu'à présent. Si vous tentiez d'ajouter du typage statique à Ruby, vous le paralyseriez, si vous tentiez de le retirer à Haskell, vous l'écrasiez. Contrairement à cela: si vous le retiriez de C, les gens ne s'en rendraient pas compte et si vous le retiriez de Java, certains pourraient vous en remercier.

D'après mon expérience personnelle, je peux vous dire ceci: j'aime Ruby. Cela a élargi mes horizons et la façon dont je conçois les systèmes. À mon humble avis, il devrait être utilisé pour enseigner aux gens la programmation en premier lieu. Il est discret, puissant, concis, amusant. Je comprends pourquoi quelqu'un venant d'une langue orthodoxe l'appréciera.
Sur le long terme cependant, le typage statique permet de reporter le travail à l'analyseur statique et avec l'inférence de type, cela vient essentiellement sans frais. Le résultat est un code plus facile à gérer et qui s'exécute souvent plus rapidement.

Mais encore une fois, la saisie statique seule ne peut rien faire. C'est une question de combinaison. Je pense que quelque part entre F #, Scala, Nemerle, OCaml ou haXe, vous pouvez trouver votre propre optimum. Mais cela dépend finalement de vous, car le langage devrait vous permettre d'intégrer vos pensées sans effort, au lieu de vous forcer à les contourner. Et après tout, rien ne rapporte plus de productivité que si la programmation est amusante.

6
back2dos

Personnellement, la seule raison pour laquelle la frappe dynamique serait utile est que vous êtes un dactylographe vraiment lent ou que vous construisez des fonctions/méthodes/méthodes géantes difficiles à naviguer. Vous devez également entrer dans le problème des tests unitaires. Les types dynamiques nécessitent (sauf si vous aimez écrire du code cassé) des tests unitaires vigoureux (pour vous assurer que vos types dynamiques ne explosent pas de manière inattendue (c'est-à-dire que la variable est principalement canard, mais accidentellement parfois)). La statique fera beaucoup plus d'efforts pour éviter cela (et oui, vous pouvez plaider en faveur de tests unitaires vigoureux)

3
Paul

Je pense tout d'abord qu'il faut définir la "productivité". Que signifie et comprend la "productivité"?

Si par "plus productif" vous voulez dire écrire moins de lignes de code pour implémenter la même fonctionnalité, alors oui, les langages de programmation à typage dynamique sont plus "productifs" que les langages à typage statique.

Cependant, si vous considérez également le temps consacré au débogage et à la correction des bogues, les langages de typage dynamique peuvent ne pas être aussi productifs, car les langages de typage dynamique ont tendance à pousser la vérification des erreurs à l'exécution tandis que, en revanche, les langages de typage statique peut effectuer une vérification des erreurs au moment de la compilation. Comme il est communément admis que, généralement, plus un bogue est détecté tard, plus il est coûteux de le corriger. Par conséquent, le code de typage dynamique peut entraîner une productivité généralement égale ou peut-être même inférieure à la productivité du code de typage statique.

0
yaobin