La dactylographie statique vaut-elle la peine?

108

J'ai commencé à coder en Python principalement là où il n'y a pas de sécurité de type, puis je suis passé à C # et Java où il y en a. J'ai découvert que je pouvais travailler un peu plus rapidement et avec moins de maux de tête avec Python, mais là encore, mes applications C # et Java ont un niveau de complexité beaucoup plus élevé. Je suppose que je n'ai jamais fait d'un vrai test de stress pour Python.

Les camps Java et C # donnent l’impression que, sans le type de sécurité en place, la plupart des gens se heurteraient à toutes sortes de bugs horribles qui resteraient à droite et ce serait plus difficile que sa valeur.

Il ne s’agit pas d’une comparaison linguistique, veuillez donc ne pas traiter de problèmes tels que compilé ou interprété. La sécurité de type vaut-elle le coup à la vitesse de développement et à la flexibilité? POURQUOI?

aux personnes qui voulaient un exemple de l’opinion selon laquelle la frappe dynamique est plus rapide:

"Utilisez un langage typé de manière dynamique pendant le développement. Il vous permet de réagir plus rapidement, de prendre des délais et de développer rapidement." - http://blog.jayway.com/2010/04/14/static-typing-is-the-root-of-all-evil/

Morgan Herlocker
la source
15
Cette question est l'opposé de Quels sont les arguments en faveur d'un typage faible? .
Nicole
8
@Prof Plum: puis-je exiger une preuve de la rapidité de développement et de la flexibilité? Puisque nous parlons d'un aspect particulier du type Sécurité , qui utilise Javaou C#ne serait pas concluant, leur façon de le fournir n'est PAS la seule ...
Matthieu M.
32
Avec une diligence dans un langage strict, vous pouvez minimiser les "maux de tête" et vous pourriez même voir une augmentation de vitesse due à l'auto-complétion IDE, à la génération de code et aux conseils de code.
Nicole
9
@Prof Plum: Je comprends, je ne m'attends pas à ce que vous (ou qui que ce soit vraiment) ayez entièrement testé chaque langue jamais créée ^^ Le problème est que la plupart des gens que j'ai vus se sont plaints de certains aspects spécifiques des langages de programmation (Static La frappe arrive souvent) se plaignent généralement d'une mise en œuvre particulière et ne le réalisent pas.
Matthieu M.
5
@Prof Plum, tout ce que l'article de blog dit vraiment sur la vitesse est l'affirmation chauve "Quiconque a travaillé sérieusement avec un langage moderne à typage dynamique comme Ruby ou Smalltalk, sait qu'il est plus productif." Aucun exemple concret de la façon dont, en pratique, cela accélère le développement.
Carson63000

Réponses:

162

C'est en quelque sorte un mythe que les programmeurs n'ont pas à s'inquiéter des types dans des langages à typage dynamique.

Dans des langues typées dynamiquement:

  • Vous devez toujours savoir si vous travaillez avec un tableau, un entier, une chaîne, une table de hachage, une référence de fonction, un dictionnaire, un objet ou autre.

  • Si c'est un objet, vous devez savoir à quelle classe il appartient.

  • L'affectation d'un de ces types à une variable ou à un paramètre de fonction censé être un autre type est presque toujours une erreur.

  • À un niveau inférieur, des éléments tels que le nombre de bits ou signé par rapport à non signé doivent toujours être pris en compte si vous remplissez un paquet TCP, par exemple.

  • Vous pouvez rencontrer des problèmes où vous obtenez un zéro où vous vouliez vraiment une chaîne vide. En d'autres termes, vous êtes toujours en train de déboguer des bogues d'incompatibilité de types. La seule différence est que le compilateur ne détecte pas les erreurs.

  • Je dirais que vous ne sauvegardez même pas beaucoup de frappe - parce que vous avez tendance à vouloir documenter dans les commentaires le type de vos paramètres de fonction au lieu de le documenter dans votre code. C'est pourquoi les blocs de commentaires de style doxygen sont beaucoup plus populaires en pratique dans le code dynamiquement typé, alors que dans les langages statiquement typés, vous ne les voyez généralement que pour les bibliothèques.

Cela ne veut pas dire que la programmation dans les langues dynamiquement tapées ne se sent plus agréable parce que le compilateur est pas toujours sur le dos, et les programmeurs expérimentés ne tendent pas à avoir du mal à trouver et à corriger le type de bugs qui typage statique attraperait de toute façon , mais c’est un problème complètement différent d’une prétendue augmentation de l’efficacité ou de la réduction du taux de bogues, pour lequel le typage dynamique est au mieux, même avec le typage statique.

utilisateur61852
la source
10
Je devrais contester le fait que des programmeurs expérimentés ne créent pas / ne présentent pas ce genre de bugs. Les bons développeurs qui sont humbles et reconnaissent la possibilité qu’ils commettent des erreurs (et les développeurs expérimentés ne le sont pas toujours) sont moins susceptibles de créer ces bogues.
Jay Jay Jay
12
Je suis tout à fait d’accord avec "Je dirais que vous n’économisez même pas beaucoup de frappe". Vous finissez par documenter les types dans les commentaires et les vérifier dans vos tests, ce qui nécessite éventuellement davantage de dactylographie et de maintenance (après tout, vous devez vous rappeler de mettre à jour lesdits commentaires chaque fois que vos types changent, et le plus souvent vous ne le ferez pas. ).
Severyn Kozak
Dans notre boutique Python, nous passons beaucoup plus de temps à documenter les types que nous épargnons par rapport à un langage verbeux typé statiquement, comme C # ou Java. Il est également intéressant de noter que la nouvelle génération de langages comme Go et Rust utilise l'inférence de type, vous saisissez donc "x: = new (Object)" au lieu de "Object x = new Object ()".
Weberc2
Je suis d'accord avec vous lorsque vous dites que le langage dynamique est plus agréable, mais je ne sais pas pourquoi. Avez-vous une explication à cela?
Rodrigo Ruiz
Au lieu de donner le type des variables, vous pouvez utiliser des valeurs par défaut ou des tests unitaires (doctests en ligne) en Python. De plus, en Python, vous pouvez parfois avoir des erreurs bizarres avec des erreurs d’orthographe [moins susceptibles de se produire si vous utilisez la saisie semi-automatique qui peut souvent être utilisée bien qu’elle ne soit pas toujours en veille dans les langages dynamiques] et que vous devez déterminer si self.bread = 5 est en train d’être introduit. pain ou le redéfinir.
aoeu256
123

À mesure que les types deviennent plus forts, ils peuvent vous aider davantage - si vous les utilisez correctement au lieu de les combattre. Concevez vos types de manière à refléter votre espace de problèmes et les erreurs de logique sont plus susceptibles de devenir des incohérences de types à la compilation plutôt que des plantages à l'exécution ou des résultats non-sens.

geekosaur
la source
37
+1! "Les erreurs de logique risquent davantage de devenir des incohérences de types à la compilation plutôt que des plantages à l'exécution ou des résultats absurdes": Très bonne réponse! Lorsque je prends plus de temps pour concevoir mes types, le code suit plus naturellement et il est souvent correct dès qu'il est compilé. Concevoir un type signifie comprendre un domaine et ses opérations.
Giorgio
78

Disclaimer: Je suis un amoureux du type;)

Il est difficile de répondre à votre question: quels sont ces compromis ?

Prenons un exemple extrême: Haskell , il est typé de manière statique. Peut-être l'un des langages les plus typés qui existe, en fait.

Cependant, Haskell prend en charge la programmation générique , en ce sens que vous écrivez des méthodes qui fonctionnent avec tout type conforme à un certain concept (ou interface).

De plus, Haskell utilise l’ inférence de type , vous évitant ainsi de déclarer le type de vos variables. Ils sont calculés statiquement lors de la compilation, un peu comme un interprète Python les calculerait en exécutant le programme.

J'ai constaté que la plupart des gens qui parlaient de typage statique se plaignaient de quelque chose d'autre (verbosité, peine de changer de type en faveur d'un autre), mais Haskell ne présente aucun de ces problèmes, tout en étant typé de manière statique ...


Exemple de brièveté:

-- type
factorial :: Integer -> Integer

-- using recursion
factorial 0 = 1
factorial n = n * factorial (n - 1)

Hormis le support intégré, il est difficile d’être plus bref.

Exemple de programmation générique:

> reverse "hell­o" -- Strings are list of Char in Haskell
=> "olleh"
> reverse [1, 2, 3, 4, 5]
=> [5,4,3,2,1]

Exemple d'inférence de type:

> :t rever­se "hell­o"
:: [Char]

qui peut être calculé simplement:

  • "hello"est une liste de Char(exprimée en [Char])
  • reverseappliqué à un type [A]retourne un type[A]

Essayez-le dans votre navigateur

Matthieu M.
la source
4
Pour défendre les intérêts du diable, un compromis en faveur des langages dynamiques (du moins tout en prototypant) est que, dans la mesure où les déclarations de type peuvent servir le même objectif que certains tests unitaires, elles peuvent également solidifier les interfaces de la même manière que les tests unitaires ( mais certainement avec moins de frais généraux). En outre, les langages à typage statique sans contrainte, bien que plus sûrs, nécessitent un transtypage de type explicite (notamment lorsqu'un type n'est pas assez générique), ce qui peut nuire à la concision.
TR
7
Je ne connais pas Haskell mais +1 pour "en fait, nous nous sommes plaints de quelque chose d'autre (verbosité, douleur de changer de type en faveur d'un autre)"
Nicole
1
@Aidan: Haskell est une langue en évolution. Haskell 98 était une amélioration par rapport à Haskell 1.4; Haskell 2010 était une amélioration par rapport à cela. Dans le même temps, il convient de noter que pendant sa vie, la raison d'être de Haskell était d'aider à explorer les systèmes de types; Les classes de types multi-paramètres sont un exemple d’endroit où il a réussi à élucider une extension de système de types utile. (D'un autre côté, les dépendances fonctionnelles sont en passe de devenir une impasse.)
geekosaur Le
4
@ Mattthieu: WRT "Peut-être l'un des langages les plus fortement typés qui existe, en fait.", Je vais voir votre Haskell et vous élever Agda et Coq . (
J'accorderai
1
@ Matthieu: Les assistants de preuve sont une application directe de la correspondance Curry-Howard. Ils sont donc au cœur des langages de programmation (bien que leurs bibliothèques standard soient plutôt limitées). Ils sont à la pointe de la recherche sur les types dépendants car vous avez besoin de types dépendants pour bien utiliser la correspondance "les types sont des propositions".
geekosaur
37

J'aime les langages à typage statique et à typage dynamique. Les deux plus gros avantages de type safety pour moi sont:

1) Vous pouvez souvent déduire ce que fait une fonction uniquement de sa signature de type (ceci est particulièrement vrai dans les langages fonctionnels comme Haskell).

2) Lorsque vous effectuez un refactor significatif, le compilateur vous dit automatiquement tout ce que vous devez faire pour que tout fonctionne correctement. Lorsque je refacture quelque chose en C ++, ma procédure est souvent simplement a) changer la partie que je sais que je veux changer, puis b) corriger toutes les erreurs de compilation.

Dfan
la source
Exactement pareil avec moi, et chaque fois que je veux refactoriser quelque chose (j'utilise principalement golang / typescript / java), oui, ces 2 étapes sont celles dont tout le monde aurait besoin. changez une partie, puis corrigez toutes les erreurs de compilation :) réponse parfaite.
Nishchal Gautam
29

Personnellement, je trouve que la sécurité de type me permet de développer plus rapidement mon travail actuel. Le compilateur effectue beaucoup de vérifications de cohérence pour moi presque au fur et à mesure que je tape, ce qui me permet de me concentrer davantage sur la logique métier que je suis en train de mettre en œuvre.

En résumé, bien que je perde un peu de flexibilité, je gagne un peu de temps que je passerais sinon à traquer les problèmes de type.

Michael K
la source
13

Il y a beaucoup d'opinions fortes autour du débat mais évidemment ce n'est pas une question d'opinion, c'est une question de faits . Donc , nous devrions envisager la recherche empirique . Et la preuve en est claire:

Oui , le typage statique en vaut la peine - et pas seulement un peu, mais de manière substantielle . En fait, des preuves solides montrent que le typage statique peut réduire le nombre de bogues dans le code d'au moins 15% (et il s'agit d'une estimation basse, le pourcentage réel est presque certainement supérieur). C'est un nombre choquant : je pense que même la plupart des partisans du typage statique n'auraient pas pensé que cela faisait une différence aussi radicale.

Considérez ceci: si quelqu'un vous disait qu'il y avait un moyen simple de réduire les bugs de votre projet de 15% du jour au lendemain, cela devrait être une évidence. 1 C’est presque la solution miracle.

La preuve est présentée dans le document Taper ou ne pas taper: Quantifier les bogues détectables en JavaScript par Zheng Gao, Christian Bird et Earl T. Barr. J'encourage tout le monde à le lire, c'est un article bien écrit qui présente une recherche exemplaire.

Il est difficile de résumer succinctement la rigueur avec laquelle les auteurs ont effectué leur analyse, mais voici un aperçu (très approximatif):

TypeScript et Flow sont deux langages de programmation basés sur JavaScript qui, tout en restant compatibles, ajoutent des conseils de type et une vérification de type statique. Cela permet d'augmenter le code existant par types, puis de le vérifier.

Les chercheurs ont collecté des projets Open Source écrits en JavaScript à partir de GitHub, ont examiné les rapports de bogues résolus et ont tenté de réduire chacun des bogues signalés à un morceau de code qui serait intercepté par le vérificateur de type statique de TypeScript ou Flow. Cela leur a permis d'estimer qu'une limite inférieure du pourcentage de bogues pourrait être corrigée en utilisant un typage statique.

Les chercheurs ont pris des précautions strictes pour que leur analyse ne considère pas un bogue lié à un type comme étant lié à un type. 2

Par rapport aux études antérieures, cette nouvelle étude présente des atouts particuliers:

  • Il existe une comparaison directe entre le typage statique et le typage dynamique, avec peu (le cas échéant) de facteurs de confusion, car la seule différence entre JavaScript et TypeScript / Flow est le typage.
  • Ils effectuent la réplication sur plusieurs dimensions en vérifiant à la fois TypeScript et Flow (c.-à-d. Différents systèmes de types) et en demandant à différentes personnes de reproduire l'annotation de type (manuelle) pour corriger les bogues. Et ils le font sur un grand nombre de bases de code issues de différents projets.
  • Le document mesure l'impact direct du typage statique sur les bogues corrigables (plutôt que sur une qualité plus vague).
  • Les auteurs définissent un modèle rigoureux de ce qu'il faut mesurer, et comment, dès le départ. De plus, leur description est incroyablement claire et facilite l’analyse des défauts (c’est toujours bon quand un document de recherche s’ouvre aux attaques: si aucune attaque ne parvient à entamer ses arguments, elle en sortira encore plus forte). 3
  • Ils effectuent une analyse de puissance appropriée afin que la taille de leur échantillon soit suffisante, et leur analyse statistique ultérieure est étanche.
  • Ils sont trop conservateurs pour exclure les explications confuses et ne mesurent qu’une seule pièce mobile. En outre, ils limitent leur analyse aux bogues immédiatement réparables en incluant des types et excluent tout ce qui peut nécessiter un refactoring plus avancé pour tenir compte de la frappe. Donc, en réalité, l'effet est vraisemblablement beaucoup plus important, mais certainement pas inférieur à ce qu'ils ont rapporté.
  • Et finalement, ils ne trouvent pas un léger effet, mais une différence stupéfiante . Malgré leur procédure trop conservatrice, même au bas de l'intervalle de confiance de 95%, ils s'aperçoivent qu'au moins 10% des bogues disparaîtraient simplement avec un minimum de vérifications de type.

À moins d’un défaut fondamental dans le document que personne n’a encore découvert, le document présente de manière concluante un avantage considérable du typage statique, et ce, à peu de frais. 4


Sur le plan historique, la recherche sur les disciplines de dactylographie dans la programmation a connu des débuts difficiles, car pendant longtemps, les preuves n’étaient pas claires du tout. La raison en est qu’il n’est pas facile de faire des expériences systématiques pour examiner l’effet du typage statique par rapport au typage dynamique: une expérience systématique doit isoler l’effet recherché. Et malheureusement, nous ne pouvons pas isoler l’effet de la discipline de frappe, car elle est liée aux langages de programmation.

Il existait en fait des langages de programmation autorisant à la fois le typage statique et dynamique dans différents dialectes (par exemple, VB avec Option Strict Onou Off, ou le type Lisp statique). Cependant, ceux-ci n'étaient pas bien adaptés à une comparaison directe, surtout parce qu'il n'existait aucune base de code suffisamment grande pour permettre une comparaison directe. Au mieux, nous pourrions les comparer dans des «paramètres de laboratoire», où les sujets de test résolvent une tâche de manière aléatoire dans la variante typée statiquement ou dynamiquement du langage.

Malheureusement, ces tâches de programmation artificielles ne modélisent pas bien l’utilisation dans le monde réel. En particulier, beaucoup d’entre eux ont une petite portée et résolvent un problème bien défini qui peut être résumé sur une demi-page de texte.

Heureusement, c'est du passé, parce que TypeScript, Flow et JavaScript sont les mêmes langages, à l'exception du typage statique, et qu'il existe un vaste ensemble de données de code et de bogues réels dans lesquels échantillonner.


1 Inspiré par une citation du document original.

2 Je ne suis pas entièrement satisfait de cela: l'un des principaux atouts des langages à typage statique est que les problèmes apparemment apparentés au type peuvent être formulés de manière à pouvoir être contrôlés statiquement. Cela transforme de nombreuses erreurs de logique en erreurs de type, ce qui augmente considérablement le nombre de bogues pouvant être détectés par le typage statique. En fait, le document classe grossièrement les bogues non liés au type et je soutiens qu’un grand pourcentage d’entre eux pourrait en fait être attrapé par le typage statique.

3 J'invite n'importe qui, en particulier les partisans du typage dynamique, à rechercher des failles non résolues dans l'analyse. Je ne pense pas qu'il y en ait beaucoup (le cas échéant) et je suis convaincu qu'aucun défaut éventuel ne modifierait de manière significative le résultat.

4 Je soupçonne que le coût réel du typage statique dans les projets réels de grande envergure est inexistant, car il devient alors une partie naturelle de l’architecture et pourrait même simplifier la planification. La correction des erreurs de type statique prend du temps, mais beaucoup moins que les erreurs découvertes ultérieurement. Cela a fait l'objet de nombreuses études empiriques et connues depuis des décennies (voir par exemple Code Complete ).

Konrad Rudolph
la source
3
Je sais que la réponse à cette question est tardive, mais j'estime que les nouvelles preuves (que j'explique ici) modifient complètement le débat statique / dynamique.
Konrad Rudolph
2
C'est certainement intéressant, mais je me demande à quel point cela est lié au système de types particulier de javascript. Le système de types Python (en particulier Python3) est beaucoup plus strict avec beaucoup moins de conversions implicites.
Peter Green
@ Peter Green Oui, c'est sans aucun doute vrai. Peut-être avons-nous de la chance, et les indications de caractères de Python mèneront à une analyse similaire (bien que j'en doute, car l'objectif déclaré dans PEP484 & PEP526 est de ne pas implémenter de typage statique).
Konrad Rudolph
1
En lisant simplement le résumé, je peux déjà dire que la méthodologie est fondamentalement imparfaite. Vous ne pouvez pas utiliser une base de code écrite en utilisant une discipline, puis simplement ajouter des types pour justifier des arguments dans une discipline totalement différente. Le code écrit en tant que discipline statique semble fondamentalement très différent de la discipline dynamique, vous ne devriez pas écrire Java en Python, tout comme vous ne devriez pas écrire Python en Java. Même les textes dactylographiés et javascript sont des langages fondamentalement différents, malgré des similitudes superficielles.
Lie Ryan
2
@LieRyan Si quoi que ce soit qui rend l'analyse trop conservatrice, comme indiqué dans ma description et ailleurs. Cela n'invalide nullement l'analyse. Votre estimation de 1% est, honnêtement, risible. C'est complètement éteint, votre intuition vous laisse tomber. De même, votre caractérisation des problèmes liés au typage statique est typique d'un praticien du typage dynamique qui a peu d'expérience réelle avec le typage statique moderne (c'est-à-dire pas uniquement Java).
Konrad Rudolph
12

La sécurité de type vaut-elle le coup à la vitesse de développement et à la flexibilité?

Donc, vraiment, cela revient à ce que vous faites. Si vous programmez, par exemple, les systèmes de secours pour avions, le type sécurité est probablement la voie à suivre.

Langage dynamique vs programmation en langage statique sont vraiment deux animaux différents. Ils exigent tous deux une approche fondamentalement différente l'un de l'autre. Vous pouvez principalement porter une méthode d'approche entre statique et dynamique, mais vous perdrez les avantages de l'autre.

C'est vraiment un état d'esprit. Est-ce que l'un est meilleur que l'autre? Cela dépend vraiment de qui vous êtes et comment vous pensez. La plupart des gens avec qui je travaille ne toucheraient jamais un langage dynamique s'ils n'y étaient pas obligés, car ils estimaient qu'il y avait trop de marge d'erreur. Ont-ils tort de penser cela? Non, bien sûr que non, mais cela signifie qu'ils ont compris que leur approche consistant à appliquer leur style de codage ne fonctionnerait pas dans un environnement dynamique. Les autres personnes avec lesquelles je vais aux groupes d’utilisateurs sont exactement le contraire. Ils trouvent la dactylographie statique trop lourde car elle limite leur approche à la résolution de certains types de problèmes.

Je peux honnêtement dire que je saute beaucoup entre JavaScript et C #. Maintenant, connaître et travailler dans les deux langues influence quelque peu l’autre, mais en vérité, le code que j’écris dans chacune d’entre elles est totalement différent de l’autre. Ils nécessitent une approche différente, car ils sont fondamentalement différents. Ce que j’ai trouvé, c’est que si vous vous dites: "Man, c’est tellement plus difficile de le faire en langage X", votre approche est probablement un peu fausse. Voici un exemple, les gens parlent de la façon de faire "Pythonic". Cela signifie que le langage Python fonctionne de manière à simplifier les problèmes. Le faire autrement est généralement plus difficile et plus lourd. Vous devez surmonter la bosse de savoir comment une langue fonctionne vraiment pour que cela fonctionne pour vous. Il'

kemiller2002
la source
Cela faisait un moment que je pensais que les langages de programmation ne devraient cacher que des fonctionnalités de votre code auxquelles vous n'avez jamais besoin de penser. Cela vaut pour obtenir du code machine jusqu’à un niveau plus élevé, comme Java, car ce niveau d’implémentation plus bas n’est en principe jamais une affaire à traiter. Ce n'est pas le cas pour les types d'objet. À mon avis, le typage dynamique ne fait que rendre la programmation plus difficile, car il introduit toute une classe d'erreurs que vous devez vous attraper.
MCllorf
7

Une question similaire venait juste d'être posée récemment: Langages dynamiques vs statiques pour sites Web

Pour reformuler l'essentiel de ma réponse:

À mesure que les systèmes grandissent, les langages à typage statique garantissent la robustesse au niveau des composants et donc la flexibilité au niveau du système.

Oui, Java est strictement dactylographié et oui, Java est nul (aucune infraction. C'est horrible. Excellente plate-forme et écosystème, mais l'un des pires langages de tous les temps (actuellement utilisé)).
Mais en déduire que la dactylographie stricte est une erreur. C'est comme pointer du doigt sur PHP et inférer du tapage dynamique, c'est nul (encore une fois, pas d'offense. Ça s'améliore lentement, je vous le dis).

Personnellement, je réalise l' essentiel de mon développement dans haXe , qui a un système de types statique. Non seulement il est significativement plus expressif que celui de Java et demande beaucoup moins d'effort en raison de l'inférence de type, mais il est également facultatif. Si cela vous gêne, vous la contournez.

La sécurité des types est une fonctionnalité (c’est quelque chose que beaucoup de langages supposés de haut niveau ne comprennent pas bien) pour vous aider à ne pas vous tirer dans le pied .
Et tout langage réussi dynamiquement typé serait simplement préférable, si vous aviez l'option de faire vérifier votre type de code à volonté.
Par exemple, j'ai certainement aimé expérimenter Ruby, mais c'était principalement parce que Ruby est entièrement orienté objet, ce qui est parfaitement orthogonal à la présence d'un système de type compilation.

Je pense que l'affirmation selon laquelle les systèmes de types statiques sont obstrus est simplement basée sur le manque de connaissance des bons systèmes de types statiques. Un certain nombre de langues font bien les choses, le haXe en fait partie et n’est peut-être même pas la meilleure à cet égard.

Exemple de code haXe:

class Car {
    public function new();
    public function wroom() trace('wroooooooom!')
}
class Duck {
    public function new();
    public function quack(at) trace('quackquack, ' + at + '!')
}

function letQuack(o) o.quack();
letQuack(new Car());
letQuack(new Duck());

Cela produira une erreur de compilation:

Car should be { quack : Void -> Unknown<0> }
Car has no field quack
For function argument 'o'
Duck should be { quack : Void -> Unknown<0> }
Invalid type for field quack :
to : String -> Void should be Void -> Unknown<0>
For function argument 'o'

Vous ne pouvez pas vraiment prétendre que j'ai dû faire beaucoup d'efforts pour la sécurité de type.

Dire que vous n'avez pas besoin de sécurité de type, parce que vous avez des tests, c'est encore plus idiot. Écrire des tests est ennuyeux et répétitif. Et je ne veux vraiment pas écrire un test, juste pour découvrir, qu'une instance de Car ne va pas charmer et qu'un Canard a besoin de quelqu'un à qui charler.

À la fin de la journée, vous constaterez que peu importe les frais généraux liés à la sécurité, celle-ci finit par être amortie (même en Java - même si ce n’est peut-être pas si tôt).

arrière back2dos
la source
En Python, les doctests sont simplement copiés et collés à partir de repl / shell, en tant que source de documentation et de vérification ultérieure. docs.python.org/3/library/doctest.html
aoeu256
5

Pour une raison quelconque, je ne commets plus souvent d'erreurs liées au type d'objet. Dans des langages tels que C #, je suis plus susceptible de commettre des erreurs liées aux cast d'exécution que de commettre une erreur de sécurité de type détectable par le compilateur, qui, à mon avis, est généralement causée par le besoin occasionnel de contourner le caractère statique d'un objet statique. langue dactylographiée. Lorsque j'écris en ruby, le code suggère assez fortement le type d'objet et la disponibilité d'une REPL signifie que j'ai déjà vérifié de manière expérimentale que la méthode / les attributs souhaités existaient ou qu'un test unitaire serait exécuté. essentiellement la même chose, donc je rencontre aussi rarement des problèmes de sécurité de type en rubis.

Mais cela ne veut pas dire que les systèmes statiques ne peuvent pas être meilleurs qu’ils ne le sont.

Dans les langages à typage statique, le système de types est également très important. Par exemple, avec quelque chose comme la monade Some dans des langages fonctionnels (type <Some>: = yes x | no), vous obtenez des contrôles au moment de la compilation qui empêchent essentiellement la redoutable NullReferenceException commune dans la plupart des systèmes de types; lorsque le code de correspondance de modèle est exécuté, des erreurs de compilation vous signalent que vous n'avez pas réussi à gérer la condition null (si vous utilisez ce mécanisme pour déclarer le type). Vous réduisez également les types d'erreur similaires lorsque vous utilisez des éléments tels que |> l'opérateur de pipeline en F #.

Dans la tradition de typage statique de Hindley – Milner, vous pouvez créer des choses qui vous apportent bien plus que la garantie qu'un type prétend supporter l'interface X, et une fois que vous avez ces choses, je dirais que le système à typage statique devient complexe plus précieux.

Lorsque cela n’est pas une option, les extensions Design By Contract vers C # peuvent ajouter un autre ensemble de mécanismes qui augmentent la valeur du système de types statiques, mais ils nécessitent toujours plus de discipline que certains de ces paradigmes fonctionnels.

JasonTrue
la source
5

Ça dépend.

Les modes de défaillance humaine sont souvent statistiques. Une vérification de type forte réduit la probabilité de certains types de défaillances humaines (provoquant un code erroné). Mais le fait d’échouer ne signifie pas toujours que vous le ferez (Murphy ne résiste pas).

Le coût dépend de cette réduction du risque d'échec potentiel.

Si vous écrivez du code pour une centrale nucléaire ou un système ATC, toute réduction du mode de défaillance humaine peut être extrêmement importante. Si vous prototypez rapidement une idée de site Web qui n'a aucune spécification et dont les conséquences en matière de défaillance sont quasiment nulles, la réduction des modes de défaillance ou des probabilités peut ne pas vous apporter grand-chose, mais peut vous coûter cher en temps de développement (plusieurs frappes au clavier, etc.), et dans les cellules cérébrales distraites par la mémorisation du type actuel requis.

hotpaw2
la source
3
Votre scénario de prototypage rapide semble être faux dans l'article de Paul Hudak sur une étude de la marine américaine nécessitant de développer une simulation de type AEGIS dans différentes langues, dont Haskell. Il répond à presque tous vos critères: il s’agissait d’un prototypage rapide, les exigences étaient mal définies et le coût de l’échec était presque nul (il s’agissait là d’une expérience extrêmement informelle). Haskell est sorti vainqueur dans toutes les catégories: temps de développement, dépassement des exigences, nécessitant moins de COL, et production du seul exemple concret parmi tous les concurrents!
Andres F.
2
Le papier: Haskell vs…, une expérience dans la productivité de prototypage de logiciel - Paul Hudak et Mark P. Jones . Il décrit les résultats d'une expérience commandée par l'ARPA et l'US Navy.
Andres F.
Le gagnant n'était-il pas Relational Lisp? J'aurais aimé qu'il y ait des vidéos montrant des personnes codant des choses en Lisp avec toutes ces extensions puissantes et étranges comme Shen (un framework relationnel-logique qui vous permet de donner des types dépendants au code et de combiner du code de type avec du code non-type ), cadres super-CLOS avec envoi de prédicats, etc.
aoeu256
4

Il y a eu beaucoup de systèmes très compliqués écrits en Lisp, et je n'ai entendu aucun Lisper se plaindre de vouloir du typage statique. Lorsque je travaillais avec cela, je ne me souvenais pas des problèmes qui auraient ralenti beaucoup un système de type statique (et vous pouvez spécifier des types de manière statique dans Common Lisp).

De plus, les langages classiques à typage statique ne semblent pas bien adaptés à la détection des erreurs. Dans la conception d' une mise en page, ce qui est important est qu'un certain nombre est une mesure verticale sur la page, et non pas que ce soit int, unsigned, floatou double. Le compilateur, par contre, marquera souvent les conversions de type qu’il juge dangereuses, et me laissera heureusement ajouter une mesure verticale et le nombre de caractères d’une chaîne. Cette faiblesse du système de types statiques était l’idée originale de la notation hongroise de Simonyi, avant qu’elle ne soit bâtie en une vaine inutilité.

David Thornley
la source
4

Les types sont des contraintes sur les interfaces. Ils constituent donc un sous-ensemble de ce que vous souhaitez peut-être tester avec des tests unitaires. Par conséquent, de nombreux compromis sont similaires:

  • Les types statiques indiquent plus tôt si le code répond ou non aux exigences pouvant être exprimées par le système de types, en échange de retarder le retour de la construction d'un élément peu fonctionnel (comme les commentaires des clients ou des tests de niveau supérieur).
  • Le fait de savoir que le code répond à certaines exigences peut faciliter le refactoring et le débogage, mais cela alourdit également les modifications apportées aux interfaces et aux exigences.
  • En particulier si un langage à typage statique manque de coercition, il offre une sécurité accrue contre le code utilisé sur les données qui causeraient des bogues (réduisant ainsi le besoin de conditions et d'assertions), mais des contraintes trop restrictives imposent à l'utilisateur d'écrire davantage de code forme acceptable (telle que la conversion de type explicite).
  • Les annotations de type explicite peuvent aider à la compréhension lors de la lecture de code, ou peuvent encombrer le code avec des informations redondantes ou inutiles.
  • En fonction de la mise en œuvre, cela peut nuire à la concision. Cela dépend notamment de la nécessité ou de l'inférence des annotations de type, de la capacité du système de types à exprimer les types / interfaces génériques, de la syntaxe et de la volonté de tester les contraintes pouvant être exprimées par le système de types (c'est-à-dire, le même test est probablement plus concis en tant que fonctionnalité linguistique qu'en tant que test unitaire, mais vous n'avez peut-être pas eu l'intention de le tester).
  • De plus (mais sans lien avec TDD), les types statiques peuvent faciliter l'optimisation de la compilation, au détriment de la vérification de ces types (et prendre le temps de les vérifier et d'effectuer les optimisations), et une meilleure optimisation peut être effectuée si les données sont limitées aux types cette carte bien au matériel. Cela facilite le développement de code avec des exigences de performances, mais peut causer des problèmes pour le code qui ne répond pas bien à ces contraintes (comme indiqué au point 3).

Pour résumer, je dirais que les langages dynamiques sont particulièrement utiles pour le prototypage, alors que si vous devez être sûr que votre code est correct, vous devez privilégier un système de type fort.

T.R.
la source
3

Oui définitivement. Une chose que vous trouverez en utilisant à la fois les langages fortement typés et Python (Python est fortement typé) est que le code le mieux écrit dans les langages dynamiques a tendance à suivre les mêmes conventions que le code fortement typé. Le typage dynamique est très utile pour la sérialisation et la désérialisation, mais pour la plupart des autres choses, cela ne représente pas un avantage considérable. Et à moins que la majeure partie de votre code soit lié à la sérialisation, pourquoi abandonner la vérification d'erreur gratuite?

Mason Wheeler
la source
4
Les langages fortement typés, tels que Java et C #, gèrent la désérialisation automatiquement via l'utilisation de Reflection.
Matthieu M.
3

Morgan, j'ai une idée intéressante à essayer: typage statique + dynamique. Vous avez mentionné Python, C # et Java. Saviez-vous qu'il existe de très bons ports de Python vers .NET et Java? Dans les deux cas, les ports vous permettent d'utiliser les bibliothèques de ces plates-formes et / ou d'interagir avec le code existant. Cela vous donne plusieurs possibilités:

  1. Conservez le code existant dans un langage statique et rigide. Utilisez Python pour de nouvelles choses.
  2. Utilisez Python pour créer de nouveaux prototypes sur des plates-formes matures. Re-codez les composants que vous souhaitez conserver dans un langage plus évolué.
  3. Utilisez le langage dynamique pour les parties que vous changez souvent.
  4. Utilisez éventuellement le langage dynamique pour jouer avec des idées telles que la modification du code en cours d'exécution.
  5. Faites tout dans le langage dynamique, à l'exception des parties critiques où vous utilisez le langage fortement typé.

J'ai utilisé ces approches dès la fin des années 90 pour éviter la douleur liée au développement en C / C ++. J'avais besoin des bibliothèques natives et parfois de la performance. Pourtant, je voulais une syntaxe, une flexibilité, une sécurité optimales, etc. Ainsi, l’astuce consistait à les combiner avec soin pour obtenir les bons compromis. En pratique, il était souvent préférable de jeter le langage complet et le code hérité pour un autre langage / plate-forme.

(Remarque: une réponse l'a déjà dit, mais je tiens également à réaffirmer que le typage dynamique! = Non / le typage faible. De nombreux systèmes de frappe dynamiques utilisent un typage fort à l'intérieur. un type de variable est déterminé au moment de l'exécution, ne nécessite pas d'annotation de type et / ou peut changer lors de l'exécution.

Nick P
la source
2

Vous n'allez pas obtenir une réponse vraiment objective à cela, mais mon expérience est que la sécurité des types est précieuse jusqu'à ce que vous maîtrisiez le TDD. Une fois que vous avez une couverture lourde de tests unitaires, où les tests ont été écrits avant le code, la vérification du compilateur devient une tâche ardue et commence réellement à vous gêner.

pdr
la source
c'est une QA subjective, donc ça me va.
Morgan Herlocker
1
Quelqu'un veut expliquer les votes négatifs?
pdr
Je ne peux pas vous aider avec l'explication, mais je vous ai donné un +1, je pense que c'est une contribution utile. L'une des principales craintes du typage dynamique est que vous fassiez une modification quelque part et que vous cassiez quelque chose ailleurs en raison d'hypothèses qui auraient été appliquées par le compilateur dans un langage à typage statique. Une couverture lourde de tests unitaires vous protégera ici.
Carson63000
5
Je n'ai pas fait de vote négatif car vous avez fait valoir un argument valable, bien qu'aucune offense ne soit intentionnelle, mais votre message semble être un petit fanboy de TDD, ce qui explique probablement pourquoi les votes négatifs.
Karl Bielefeldt
@ Karl, aucune offense n'a été prise, c'était une vraie question. Je peux admettre que je peux être sans complexe pro-TDD
pdr
2

Je vois cette question se poser souvent et je pense que la qualité de votre logiciel (et le manque de bogues) a plus à voir avec votre processus de développement, la façon dont votre système est structuré et l'engagement de vous et de vos pairs envers la qualité du code.

Mon dernier travail était principalement le développement de python. J'ai travaillé pour une grande société d'hébergement Web internationale et nous avions des équipes de développement aux États-Unis, au Canada et en Corée du Sud. Cadre Web python personnalisé pour une application client frontale permettant aux utilisateurs de gérer leurs noms de domaine et leurs comptes d'hébergement Web. Backend: tout le python aussi. Service Web Python pour communiquer avec des serveurs individuels, par exemple pour créer un nouveau site d’hébergement Web, créer un nouveau blog, créer des entrées DNS dans notre système de service de noms; etc, etc. Dans mon travail actuel, les applications clientes sont toutes en java; notre produit principal est un mélange de java et de flash. Cadre Web Java personnalisé pour nos anciennes applications, guichet unique pour nos nouveaux outils internes.

Ayant travaillé dans les deux, je dois dire que cette question me dérange chaque fois que je la vois. Si vous utilisez un langage typé dynamiquement et que vous testez votre code, tout ira bien. Si le système est bien conçu et que vous suivez les normes, tout ira bien. Il n'y a jamais eu beaucoup de bugs qui sont apparus en raison de l'absence d'un type de vérification du compilateur. La plupart des bugs étaient des erreurs logiques, tout comme mon travail Java aujourd'hui.

LGriffel
la source
2

La sécurité de type vaut-elle le coup à la vitesse de développement et à la flexibilité? POURQUOI?

Le typage statique représente une nette augmentation de la vitesse et de la flexibilité du développement tout au long du cycle de vie du logiciel. Il réduit l’effort total et les inconvénients, mais déplace beaucoup d’efforts et de inconvénients au début, là où ils sont plus visibles. L'obstacle à l'entrée du code de travail est plus élevé, mais une fois passé cet obstacle (en satisfaisant le vérificateur de type), l'extension et la maintenance de ce code prennent beaucoup moins de travail.

Il y aura toujours des maux de tête dans le développement logiciel à cause de:

  • La complexité inhérente à ce que vous essayez d'accomplir

  • La faillibilité inhérente des humains, d'autant plus que nous faisons plus d'erreurs lorsque nous essayons de faire quelque chose de plus complexe

Tôt ou tard, vous devez prendre un peu de temps pour relever ces défis. Il n'y a pas moyen de contourner cela. Le typage statique répond simplement à ces défis le plus tôt possible. Le plus tôt sera le mieux, car plus tard vous découvrirez une erreur (pas une question de savoir si , mais quand ), plus il vous en coûtera pour corriger cette erreur.

Il est beaucoup moins coûteux de corriger une erreur signalée par un vérificateur de type que de déboguer une exception liée au type générée à l'exécution. Reporter la vérification de type à l'exécution ne fait que balayer le problème sous le tapis.

Jordan
la source
1

Ceci est juste ma propre opinion, mais non, je ne pense pas que le type de sécurité en vaille la peine. Pas même une seconde.

Je suis développeur depuis longtemps. Commençant avec c ++, c #, puis déplacé vers javascript (frontend et backend via node.js). Depuis que je développe en javascript, ma productivité a monté en flèche, au point de m'agacer en utilisant des langages basés sur des types. Je suis également contre la compilation, je veux que tout soit en phase d'exécution maintenant. Les langues interprétées sont vraiment où j'ai trouvé mon amour pour la programmation.

En ce qui concerne les types, je ne vois tout simplement aucun avantage. Je vois maintenant les types de la même façon que la gestion de la mémoire. Complètement inutile. Les langages de demain devraient complètement protéger le développeur de tout savoir sur les types. L'ordinateur doit comprendre les types et laisser le développeur en dehors de cela.

Voici un exemple. J'utilisais simplement Swift (le nouveau langage d'Apple) en espérant qu'il serait à la hauteur de son nom il y a un jour et j'ai essayé de le faire: var n = 1/2 ne fonctionnait pas. J'étais comme ce qui se passe ici. et puis malheureusement réalisé que je devais faire var n: Float = 1/2. Cela m'a rappelé à quel point je déteste les systèmes de type et à quel point ils constituent une aggravation inutile.

Je ferais même un autre kilomètre pour dire que je ne veux même pas de types définis par l'utilisateur (tels que Classes). Je ne veux pas du tout de types. Tout ce que je veux, c'est var et des objets. Où n'importe quel objet peut être utilisé comme n'importe quel objet. Et les objets sont dynamiques et en constante évolution. Où cela devient un problème d’exécution quant à ce qui fonctionne et ce qui ne fonctionne pas.

Les développeurs adorent dire à quel point les langages typés de manière vague ne conviennent pas aux grands projets. Mais je dirais que c'est le contraire. Les langues fortement typées sont affreuses pour les grands projets. Et si vous dites que javascript ne fonctionne pas pour les grands projets, demandez à Uber une entreprise de plus de 40 milliards d'euros qui gère tout son backend sur node.js / javascript, ou Facebook qui a commencé avec PHP.

En ce qui concerne les langages statiques, ce n'est pas bon pour les itérations rapides d'aujourd'hui. Voici un exemple simple: 10 développeurs travaillent sur un projet .net avec un serveur d'intégration continue, un développeur soumet une erreur et la construction entière est interrompue, même si les 10 développeurs travaillent sur des éléments différents, ils sont tous arrêtés et en attente. pour le développeur fautif de corriger son erreur. Tu parles d'efficace hein? Les langages système / statique sont ainsi interdépendants et rendent votre code interdépendant. Cependant, les fichiers de script ne sont jamais interdépendants. En cas de problème avec l'un des scripts, cela n'interrompt pas la production, tous les problèmes que vous rencontrez sont laissés à l'exécution. Et l'exécution ne s'arrête jamais. Ça ne casse jamais. Cela pourrait produire une sortie erronée mais cela ne fonctionne pas.

changements d'utilisateur19718
la source
1
Beaucoup de "je", pas beaucoup de substance d'argument. Et au fait, qu'une erreur "casse" ou non, la construction n'a rien à voir avec statique ou dynamique. Si vous avez des tests unitaires et que l'un d'eux échoue, "votre version est cassée" et, espérons-le, ne pas passer en production tant que cela n'a pas été corrigé
nafg
Qu'est-ce qui vous a fait penser que j'impliquais une telle chose?
nafg
Votre productivité en javascript n'a pas explosé car javascript manquait de types. Votre productivité a grimpé en flèche parce que C ++ et C # sont des langages lourds. Les types Javascript + vont réellement faire exploser votre productivité. Personne n'a dit que javascript est impossible pour les grands projets. Javascript sur de grands projets est certainement faisable. Cependant ce n'est pas idéal. Les tests unitaires remplacent la vérification de type. Ils ont également une couverture de type limitée, tandis que la vérification de type couvre 100%.
Brian Yeh
1
@BrianYeh c ++ et c # sont des langages lourds car ils sont centrés sur des types. Je viens juste de commencer à utiliser reactjs dans mon travail et ma productivité a encore chuté en raison de son utilisation incessante sur les types et les composants. si vous aimez les types et les tests unitaires, tant mieux. nous ne partageons pas tous ce style de programmation.
1
@foreyez reactjs n'a pas de types. Vous parlez probablement de flux. Les tests unitaires remplacent la vérification de type. Si vous ne possédez pas de vérification de type, vous avez besoin de davantage de tests unitaires. Les tests unitaires et les types sont des forces opposées. Votre productivité en baisse est une illusion. Toute erreur de type que vous attrapez dans une langue sans danger est une erreur non détectée dans une langue à typage dynamique. Cela semble seulement plus rapide. Le langage sans danger vous oblige à traiter ces erreurs à l’avance.
Brian Yeh
0

OUI.

J'ai travaillé dans des applications PHP, où les types ne sont pas aussi "forts" qu'en Java ou en C #. En général, je finissais par "simuler des types", parce que, pour éviter de mauvaises conversions automatiques, ou pour valider des données.

Les langues de type dynamique conviennent aux scripts de système d'exploitation et aux petites applications rapides, pas aux applications complexes.

Résumé: Si je dois choisir entre un langage de type "Type faible" ou "Type dynamique" ou un langage de programmation "Type fort" pour une application métier complexe, je choisis le langage de programmation "Type fort" .

Umlcat
la source
0

Je pense que cela vaut la peine de prendre du recul et de déterminer quand le typage dynamique pose des problèmes.

Dans un cas, une branche de code n’est pas testée du tout, mais franchement, le code qui n’est jamais testé risque de poser problème, que le typage dynamique soit utilisé ou non.

Un autre problème plus subtil est cependant la substituabilité imparfaite.

Si un type est tout à fait faux, alors à moins qu'un chemin de code particulier ne soit jamais utilisé, il est susceptible d'être détecté rapidement.

D'un autre côté, si un type est un substitut imparfait, le code peut généralement fonctionner mais se briser de manière subtile qui ne sera détectée que bien plus tard.

Deux des types les plus courants en programmation sont les nombres et les chaînes. Dans de nombreuses langues dynamiques, ils sont des substituts imparfaits les uns des autres. En javascript ou php, par exemple, si vous fournissez un nombre où une chaîne est attendue ou vice-versa, votre programme s'exécute sans générer d'erreur, mais peut se comporter de manière assez subtile.

Python a évité ce problème particulier, les nombres et les chaînes ne pouvant en aucun cas se substituer l'un à l'autre et essayer d'en utiliser un où l'autre est attendu entraînerait normalement une défaillance rapide.

Cependant, cela n’évitait pas complètement le problème de la substituabilité imparfaite. Différents types de nombres peuvent être des substituts imparfaits les uns des autres, de même que différents types de séquences.


Ce que je comprends, c’est que je ne pense pas qu’il soit possible de comparer les avantages et les coûts du typage statique et dynamique de manière générique, car je pense que les avantages et les coûts dépendent de la variation particulière du typage statique ou dynamique d’une langue. les usages.

Peter Green
la source