web-dev-qa-db-fra.com

Langages de types dynamiques versus langages de types statiques

Quels sont les avantages et les limites des langages de type dynamique par rapport aux langages de type statique?

Voir aussi : avec l'amour des langages dynamiques (un fil beaucoup plus argumentatif ...)

202
cvs

La capacité de l'interprète à déduire les types et les conversions de types accélère le temps de développement, mais peut également provoquer des échecs d'exécution impossibles à obtenir dans un langage à typage statique dans lequel vous les récupérez au moment de la compilation. Mais lequel est meilleur (ou même si cela est toujours vrai) fait l'objet de discussions animées dans la communauté ces jours-ci (et depuis longtemps).

Voici un bon exemple du problème: Dactylographie statique si possible, dactylographie dynamique en cas de besoin: la fin de la guerre froide entre les langages de programmation par Erik Meijer et Peter Drayton chez Microsoft:

Les défenseurs du typage statique soutiennent que le typage statique présente les avantages suivants: la détection précoce des erreurs de programmation (par exemple, empêcher l’ajout d’un entier à un booléen), une meilleure documentation sous la forme de signatures de type (par exemple, l’incorporation de nombres et de types d’arguments lors de la résolution de noms), plus possibilités d’optimisation du compilateur (par exemple, remplacement d’appels virtuels par des appels directs lorsque le type exact du récepteur est connu de manière statique), efficacité accrue au moment de l’exécution (par exemple, il n’est pas nécessaire que toutes les valeurs portent un type dynamique) et meilleure expérience du développeur le type du destinataire, le IDE peut présenter un menu déroulant de tous les membres applicables). Les fanatiques de typage statiques essaient de nous faire croire que "des programmes bien typés ne peuvent pas se tromper". cela semble certainement impressionnant, il s’agit là d’une déclaration plutôt vague. La vérification de type statique est une abstraction, lors de la compilation, du comportement à l’exécution de votre programme. non complet. Cela signifie que des programmes peuvent tout de même se tromper à cause de propriétés qui ne sont pas suivies par le vérificateur de types, et qu'il existe des programmes qui, s'ils ne peuvent pas se tromper, ne peuvent pas être vérifiés. L'impulsion pour rendre le typage statique moins partiel et plus complet rend les systèmes de types trop compliqués et exotiques, comme en témoignent des concepts tels que "types fantômes" [11] et "types flottants" [10]. C'est comme essayer de courir un marathon avec un ballon et une chaîne attachés à votre jambe et de crier triomphalement que vous avez failli réussir même si vous vous êtes sauvé après le premier kilomètre.

Les défenseurs des langages à typage dynamique soutiennent que le typage statique est trop rigide et que la souplesse des langages dynamiquement les rend parfaitement adaptés aux systèmes de prototypage avec des exigences changeantes ou inconnues, ou qui interagissent avec d'autres systèmes qui changent de manière imprévisible (intégration des données et des applications). Bien entendu, les langages à typage dynamique sont indispensables pour traiter un comportement de programme réellement dynamique, tels que l'interception de méthode, le chargement dynamique, le code mobile, la réflexion à l'exécution, etc. Dans la plupart des articles sur le script [16], John Ousterhout affirme que les systèmes à typage statique Les langages de programmation rendent le code moins réutilisable, plus détaillé, pas plus sûr et moins expressif que les langages de script à typage dynamique. Cet argument est littéralement repris par de nombreux partisans de langages de script à typage dynamique. Nous soutenons qu'il s'agit d'une erreur et entrent dans la même catégorie que l'argument selon lequel l'essence de la programmation déclarative consiste à éliminer les affectations. Ou, comme le dit John Hughes [8], il est logiquement impossible de rendre un langage plus puissant en omettant des fonctionnalités. Défendre le fait que remettre à plus tard la vérification du type au moment de l'exécution est une bonne chose, c'est jouer à la tactique de l'autruche avec le fait que les erreurs doivent être détectées le plus tôt possible dans le processus de développement.

138
Vinko Vrsalovic

Les systèmes de type statique cherchent à éliminer certaines erreurs de manière statique, en inspectant le programme sans l'exécuter et en essayant de prouver la validité à certains égards. Certains systèmes de types sont capables d’attraper plus d’erreurs que d’autres. Par exemple, C # peut éliminer les exceptions de pointeur nul lorsqu'il est utilisé correctement, alors que Java n'a pas ce pouvoir. Twelf a un système de types qui garantit que les preuves se termineront , " résoudre "le problème bloquant .

Cependant, aucun système de typage n'est parfait. Afin d'éliminer une classe d'erreurs particulière, ils doivent également rejeter certains programmes parfaitement valides qui violent les règles. C’est la raison pour laquelle Twelf ne résout pas vraiment le problème d’arrêt, il l’évite en jetant un grand nombre de preuves parfaitement valables qui se terminent de manière étrange. De même, le système de types de Java rejette l'implémentation de Clojure PersistentVector en raison de son utilisation de tableaux hétérogènes. Cela fonctionne au moment de l'exécution, mais le système de types ne peut pas le vérifier.

Pour cette raison, la plupart des systèmes de types fournissent des "échappements", des moyens de remplacer le vérificateur statique. Pour la plupart des langues, cela prend la forme d'un casting, bien que certaines (comme C # et Haskell) aient des modes entiers qui sont marqués comme "non sécurisés".

Subjectivement, j'aime le typage statique. Mis en œuvre correctement (indice: et non Java), un système de types statiques peut s'avérer très utile pour éliminer les erreurs avant qu'elles ne plantent le système de production. Les langues à typage dynamique ont tendance à nécessiter davantage de tests unitaires, ce qui est fastidieux dans le meilleur des cas. De plus, les langages à typage statique peuvent avoir certaines fonctionnalités qui sont soit impossibles, soit dangereuses dans les systèmes de typage dynamiques ( conversions implicites ça vient à l'esprit). Tout est une question d'exigences et de goût subjectif. Je ne voudrais pas plus construire le prochain Eclipse dans Ruby) que d'essayer d'écrire un script de sauvegarde dans Assembly ou de patcher un noyau en utilisant Java.

Oh, et ceux qui disent que " x taper est 10 fois plus productif que y en tapant "sont simplement de la fumée. La frappe dynamique peut "sembler" plus rapidement dans de nombreux cas, mais elle perd du terrain une fois que vous essayez de faire en sorte que votre application sophistiquée soit exécutée . De même, le typage statique peut sembler être le filet de sécurité parfait, mais il suffit de jeter un coup d'œil sur les définitions de types génériques les plus compliquées de Java envoie la plupart des développeurs se précipiter pour les aveugles. Même avec les systèmes de types et la productivité , il n’ya pas de solution miracle.

Remarque finale: ne vous inquiétez pas des performances lorsque vous comparez des saisies statiques avec des saisies dynamiques. Les JIT modernes tels que V8 et TraceMonkey se rapprochent dangereusement des performances du langage statique. En outre, le fait que Java soit compilé dans un langage intermédiaire intrinsèquement dynamique devrait indiquer que, dans la plupart des cas, le typage dynamique n’est pas l’énorme tueur de performances auquel certaines personnes s’associent être.

119
Daniel Spiewak

Eh bien, les deux sont très très très très mal compris et aussi deux choses complètement différentes. qui ne sont pas mutuellement exclusifs.

Les types statiques sont une restriction de la grammaire de la langue. On pourrait strictement dire que les langues typiquement statiques ne sont pas dépourvues de contexte. La simple vérité est qu’il devient peu pratique d’exprimer correctement une langue dans une grammaire sans contexte qui ne traite pas toutes ses données simplement comme des vecteurs binaires. Les systèmes de types statiques font partie de la grammaire de la langue, le cas échéant, ils la limitent simplement plus qu’une grammaire dépourvue de contexte, des vérifications grammaticales ont donc lieu en deux passages sur la source. Les types statiques correspondent à la notion mathématique de la théorie des types, tandis que la théorie des types en mathématiques limite simplement la légalité de certaines expressions. Par exemple, je ne peux pas dire 3 + [4,7] En maths, c'est à cause de la théorie des types.

Les types statiques ne sont donc pas un moyen de "prévenir les erreurs" d'un point de vue théorique, ils sont une limitation de la grammaire. En effet, à condition que +, 3 et les intervalles aient les définitions théoriques d'ensemble habituelles, si nous supprimons le système de types 3 + [4,7], Le résultat obtenu est bien défini et correspond à un ensemble. les "erreurs de type à l'exécution" n'existent théoriquement pas, l'utilisation pratique du système de types est d'empêcher des opérations qui pour des êtres humains n'auraient aucun sens. Les opérations ne sont encore que le déplacement et la manipulation de bits, bien sûr.

Le problème, c'est qu'un système de types ne peut pas décider si de telles opérations vont avoir lieu ou non, s'il est autorisé à être exécuté. Comme dans, partitionnez exactement l'ensemble de tous les programmes possibles dans ceux qui vont avoir une "erreur de type" et ceux qui ne le sont pas. Il ne peut faire que deux choses:

1: prouver que des erreurs de type vont se produire dans un programme
2: prouver qu'ils ne se produiront pas dans un programme

Cela peut sembler comme si je me contredisais. Mais ce que fait un vérificateur de type C ou Java), c’est-à-dire qu’il rejette un programme comme étant "non grammatique", ou comme il l’appelle "erreur de type" s’il peut t réussir à 2. Cela ne peut pas prouver qu'ils ne vont pas se produire, cela ne veut pas dire qu'ils ne vont pas se produire, cela signifie simplement que cela ne peut pas le prouver Il se peut très bien qu’un programme qui n’aura pas d’erreur de type soit rejeté simplement parce que le compilateur ne peut le prouver. Un exemple simple étant if(1) a = 3; else a = "string";, sûrement, puisque c’est toujours vrai, le reste -anchanch ne sera jamais exécuté dans le programme, et aucune erreur de type ne se produira, mais il ne peut pas prouver ces cas de manière générale, il est donc rejeté. C'est la principale faiblesse de nombreux langages à typage statique, qui vous protègent contre vous-même, vous êtes nécessairement protégé dans les cas où vous n'en avez pas besoin.

Mais, contrairement à la croyance populaire, il existe également des langages statiques qui fonctionnent selon le principe 1. Ils rejettent simplement tous les programmes dont ils peuvent prouver qu'ils vont provoquer une erreur de type et passent tous les programmes dont ils ne peuvent pas. Il est donc possible qu'ils autorisent les programmes contenant des erreurs de type, un bon exemple étant Typed Racket, qui hybride le typage dynamique et le typage statique. Et certains diront que vous obtenez le meilleur des deux mondes dans ce système.

Un autre avantage du typage statique est que les types sont connus au moment de la compilation, ce que le compilateur peut utiliser. Si nous Java faisons "string" + "string" Ou 3 + 3, Les deux jetons + Dans le texte représentent à la fin une opération et une donnée complètement différentes, le Le compilateur sait lequel choisir parmi les types uniquement.

Maintenant, je vais faire une déclaration très controversée ici mais gardez avec moi: le "typage dynamique" n'existe pas.

Cela semble très controversé, mais c'est vrai, les langages à typage dynamique sont d'un point de vue théorique non typés . Ce ne sont que des langages statiquement typés avec un seul type. Ou tout simplement, ce sont des langues qui sont effectivement générées grammaticalement par une grammaire sans contexte dans la pratique.

Pourquoi n'ont-ils pas de types? Étant donné que chaque opération est définie et autorisée sur chaque opérateur, qu’est-ce qu’une "erreur de type à l’exécution" exactement? C'est un exemple théorique purement un effet secondaire . Si print("string") qui imprime une chaîne est une opération, il en est de même de length(3), le premier a pour effet secondaire d'écrire string sur la sortie standard, le dernier simplement error: function 'length' expects array as argument., C'est tout. D'un point de vue théorique, il n'existe pas de langage à typage dynamique. Ils sont non typés

D'accord, l'avantage évident du langage "typé dynamiquement" est le pouvoir d'expression, un système de typage n'est rien d'autre qu'une limitation du pouvoir d'expression. Et en général, les langues avec un système de types auraient en effet un résultat défini pour toutes les opérations qui ne sont pas autorisées si le système de types était simplement ignoré, les résultats n'auraient tout simplement pas de sens pour les humains. De nombreuses langues perdent leur exhaustivité après l'application d'un système de types.

L'inconvénient évident est le fait que des opérations peuvent se produire et produire des résultats insensés pour l'homme. Pour éviter cela, les langages à typage dynamique redéfinissent généralement ces opérations, au lieu de produire ce résultat absurde, ils le redéfinissent pour avoir pour effet secondaire d'écrire une erreur, voire même d'arrêter complètement le programme. Ce n'est pas du tout une "erreur", en fait, la spécification du langage implique généralement ceci, c'est autant un comportement du langage que d'imprimer une chaîne d'un point de vue théorique. Les systèmes de types forcent ainsi le programmeur à raisonner sur le flux du code pour s'assurer que cela ne se produise pas. Ou bien, la raison pour que cela se produise peut également être utile à certains points pour le débogage, ce qui montre que ce n'est pas du tout une "erreur" mais bien propriété définie de la langue. En réalité, le seul type de "typage dynamique" de la plupart des langues est la protection contre une division par zéro. C'est ce que le typage dynamique est, il n'y a pas de types, il n'y a pas plus de types que ce zéro, c'est un type différent de tous les autres nombres. Ce que les gens appellent un "type" est simplement une autre propriété d'un datum, comme la longueur d'un tableau ou le premier caractère d'une chaîne. Et de nombreux langages à typage dynamique vous permettent également d'écrire des choses comme "error: the first character of this string should be a 'z'".

Une autre chose est que les langages à typage dynamique ont le type disponible au moment de l'exécution et peuvent généralement le vérifier, le gérer et en décider. Bien sûr, en théorie, cela n’est pas différent d’accéder au premier caractère d’un tableau et de voir ce qu’il en est. En fait, vous pouvez créer votre propre C dynamique, il vous suffit d'utiliser un seul type, tel que long long int, et d'utiliser les 8 premiers bits de celui-ci pour stocker votre "type" et écrire des fonctions en conséquence qui le vérifient et effectuent une addition flottante ou entière. Vous avez un langage typé de manière statique avec un type ou un langage dynamique.

En pratique, tout cela montre que les langages à typage statique sont généralement utilisés dans le cadre de l’écriture de logiciels commerciaux, alors que les langages à typage dynamique ont tendance à être utilisés dans le contexte de la résolution de problèmes et de l’automatisation de certaines tâches. Écrire du code dans des langages statiquement typés prend simplement beaucoup de temps et est fastidieux, car vous ne pouvez pas faire des choses qui vont bien se passer, mais le système de types vous protège toujours contre vous-même pour des erreurs que vous ne faites pas. Beaucoup de codeurs ne réalisent même pas qu'ils le font parce qu'ils sont dans leur système, mais lorsque vous codez dans des langages statiques, vous contournez souvent le fait que le système de texte ne vous permet pas de faire des choses qui ne peuvent pas se tromper. ne peut pas prouver que ça ne va pas aller mal.

Comme je l'ai noté, le terme "typé de manière statique" signifie généralement le cas 2, coupable jusqu'à preuve du contraire. Mais certaines langues, qui ne tirent pas leur système de types de la théorie des types, utilisent la règle 1: Innocent jusqu'à preuve du contraire, ce qui pourrait être l'hybride idéal. Alors, peut-être que Typed Racket est pour vous.

Aussi, bien, pour un exemple plus absurde et extrême, je suis en train de mettre en place un langage dans lequel les "types" sont vraiment le premier caractère d'un tableau, ce sont des données, des données de type "type", "type", qui est lui-même un type et une donnée, la seule donnée qui a elle-même un type. Les types ne sont ni finis ni liés statiquement, mais de nouveaux types peuvent être générés en fonction des informations d'exécution.

45
Zorf

Peut-être que le plus gros "avantage" du typage dynamique est la courbe d'apprentissage moins profonde. Il n'y a pas de système de types à apprendre ni de syntaxe non triviale pour les cas de coin tels que les contraintes de type. Cela rend la dactylographie dynamique accessible à un plus grand nombre de personnes et réalisable pour de nombreuses personnes pour lesquelles des systèmes sophistiqués de type statique sont hors de portée. Par conséquent, le typage dynamique a fait son chemin dans les contextes de l’éducation (Scheme/Python au MIT, par exemple) et des langages spécifiques à un domaine pour les non-programmeurs (par exemple, Mathematica ). Les langages dynamiques ont également gagné du terrain dans les niches où ils ont peu ou pas de concurrence (par exemple, Javascript).

Les langages à typage dynamique les plus concis (par exemple, Perl, APL, J, K, Mathematica ) sont spécifiques à un domaine et peuvent être nettement plus concis que les langages à typage statique à but général les plus concis (par exemple - OCaml ) dans les niches pour lesquelles ils ont été conçus.

Les principaux inconvénients du typage dynamique sont les suivants:

  • Erreurs de type à l'exécution.

  • Il peut être très difficile, voire pratiquement impossible d’atteindre le même niveau de correction et nécessite beaucoup plus de tests.

  • Aucune documentation vérifiée par le compilateur.

  • Mauvaises performances (généralement au moment de l'exécution, mais parfois au moment de la compilation, par exemple Schéma de Staline) et performances imprévisibles en raison de la dépendance à des optimisations sophistiquées.

Personnellement, j'ai grandi sur des langages dynamiques, mais je ne les toucherais pas avec un bâton de 40 'en tant que professionnel, à moins qu'il n'y ait pas d'autres options viables.

25
Jon Harrop

Article d'Artima dactylographie: fort ou faible, statique ou dynamique:

le typage fort empêche les opérations de mélange entre types incompatibles. Afin de mélanger les types, vous devez utiliser une conversion explicite

typage faible signifie que vous pouvez mélanger des types sans conversion explicite

Dans l'article de Pascal Costanza, Typage dynamique/statique - Une analyse basée sur un modèle (PDF), il affirme que, dans Dans certains cas, le typage statique est plus sujet aux erreurs que le typage dynamique. Certains langages à typage statique vous obligent à émuler manuellement le typage dynamique afin de réaliser "The Right Thing". On en discute à Lambda the Ultimate .

12
Mark Cidade

Cela dépend du contexte. Il y a beaucoup d'avantages qui conviennent au système typé dynamique aussi bien que pour le typé fort. Je suis d'avis que le flux de langage de types dynamiques est plus rapide. Les langages dynamiques ne sont pas limités par les attributs de classe et le compilateur ne pense pas à ce qui se passe dans le code. Vous avez un peu de liberté. De plus, le langage dynamique est généralement plus expressif et donne moins de code, ce qui est bien. Malgré cela, il est plus sujet aux erreurs, ce qui est également discutable et dépend davantage de la couverture des tests unitaires. C'est un prototype facile avec lang dynamique, mais la maintenance risque de devenir un cauchemar.

Le principal avantage du système typé statique est IDE support et analyseur de code sûrement statique. Vous êtes plus confiant en code après chaque changement de code. Le maintien est sans tracas avec de tels outils.

3
AndrewG

Il s’agit du bon outil pour le travail. Ce n'est pas mieux 100% du temps. Les deux systèmes ont été créés par l'homme et ont des défauts. Désolé, mais nous craignons et faisons des choses parfaites.

J'aime la dactylographie dynamique car elle me gêne, mais des erreurs d'exécution peuvent se produire que je n'avais pas prévues. Où typage statique peut corriger les erreurs susmentionnées, mais conduire un programmeur novice (dans les langues typées) fou en essayant de transtyper entre un caractère constant et une chaîne.

0
J.J.

Il y a beaucoup de choses différentes sur les langages statiques et dynamiques. Pour moi, la principale différence est que dans les langages dynamiques, les variables n'ont pas de types fixes; au lieu de cela, les types sont liés à des valeurs. De ce fait, le code exact à exécuter est indéterminé jusqu'au moment de l'exécution.

Dans les implémentations précoces ou naïves, la performance est un frein considérable, mais les JIT modernes s'approchent du meilleur de ce que vous pouvez obtenir avec l'optimisation des compilateurs statiques. (dans certains cas marginaux, même mieux que cela).

0
Javier