Je veux d'abord dire que Java est le seul langage que j'ai jamais utilisé, alors veuillez excuser mon ignorance à ce sujet.
Les langages typés dynamiquement vous permettent de mettre n'importe quelle valeur dans n'importe quelle variable. Ainsi, par exemple, vous pouvez écrire la fonction suivante (psuedocode):
void makeItBark(dog){
dog.bark();
}
Et vous pouvez y passer n'importe quelle valeur. Tant que la valeur a une bark()
méthode, le code s'exécutera. Sinon, une exception d'exécution ou quelque chose de similaire est levée. (Veuillez me corriger si je me trompe).
Apparemment, cela vous donne de la flexibilité.
Cependant, j'ai fait de la lecture sur les langages dynamiques, et ce que les gens disent, c'est que lorsque vous concevez ou écrivez du code dans un langage dynamique, vous pensez aux types et en tenez compte, tout comme vous le feriez dans un langage typé.
Ainsi, par exemple, lors de l'écriture de la makeItBark()
fonction, vous avez l'intention de n'accepter que des `` choses qui peuvent aboyer '', et vous devez toujours vous assurer de ne passer que ce genre de choses. La seule différence est que maintenant le compilateur ne vous dira pas quand vous avez fait une erreur.
Bien sûr, il y a un avantage à cette approche, c'est que dans les langages statiques, pour obtenir la fonction «cette fonction accepte tout ce qui peut aboyer», vous devez implémenter une Barker
interface explicite . Pourtant, cela semble être un avantage mineur.
Suis-je en train de manquer quelque chose? Qu'est-ce que je gagne réellement en utilisant une langue typée dynamiquement?
la source
makeItBark(collections.namedtuple("Dog", "bark")(lambda x: "woof woof"))
. Cet argument n'est même pas une classe , c'est un tuple anonyme. Le typage de canard ("si ça craque comme un ...") vous permet de faire des interfaces ad hoc avec essentiellement aucune restriction et sans surcharge syntaxique. Vous pouvez le faire dans un langage comme Java, mais vous vous retrouvez avec beaucoup de réflexion désordonnée. Si une fonction en Java nécessite une ArrayList et que vous souhaitez lui donner un autre type de collection, vous êtes SOL. En python, ça ne peut même pas arriver.bark()
méthode, le compilateur se plaignant lorsque vous passez quelque chose de mal mais sans avoir à déclarer une interface contenant bark ().getMember
fonction personnalisée ,makeItBark
explose parce que vous avez appelé à ladog.bark
place dedog.getMember("bark")
. Ce qui fait fonctionner le code, c'est que tout le monde accepte implicitement d'utiliser le type d'objet natif de Python.Just because I wrote makeItBark with my own types in mind doesn't mean you can't use yours, wheras in a static language it probably /does/ mean that.
Comme indiqué dans ma réponse, ce n'est pas le cas en général . C'est le cas pour Java et C #, mais ces langages ont des systèmes de type et de module paralysés, ils ne sont donc pas représentatifs de ce que le typage statique peut faire. Je peux écrire unmakeItBark
langage parfaitement générique dans plusieurs langages de type statique, même ceux non fonctionnels comme C ++ ou D.Réponses:
Les langues à typage dynamique sont uni-typées
En comparant les systèmes de types , il n'y a aucun avantage à taper dynamiquement. La frappe dynamique est un cas particulier de frappe statique - c'est un langage à frappe statique où chaque variable a le même type. Vous pouvez obtenir la même chose en Java (moins la concision) en faisant que chaque variable soit de type
Object
et en ayant des valeurs "objet" de typeMap<String, Object>
:Ainsi, même sans réflexion, vous pouvez obtenir le même effet dans à peu près n'importe quel langage de type statique, mis à part la commodité syntaxique. Vous n'obtenez aucun pouvoir expressif supplémentaire; au contraire, vous avez moins de pouvoir expressif car dans un langage typé dynamiquement, on vous refuse la possibilité de restreindre les variables à certains types.
Faire une écorce de canard dans une langue de type statique
De plus, un bon langage de type statique vous permettra d'écrire du code qui fonctionne avec n'importe quel type qui a une
bark
opération. Dans Haskell, il s'agit d'une classe de type:Cela exprime la contrainte que pour qu'un type
a
soit considéré comme Barkable, il doit exister unebark
fonction qui prend une valeur de ce type et ne renvoie rien.Vous pouvez ensuite écrire des fonctions génériques en termes de
Barkable
contrainte:Cela signifie que
makeItBark
cela fonctionnera pour tout type satisfaisantBarkable
aux exigences. Cela peut sembler similaire à uninterface
Java ou C # mais il a un gros avantage - les types n'ont pas à spécifier à l'avance les classes de types qu'ils satisfont. Je peux dire que ce typeDuck
estBarkable
à tout moment, même s'ilDuck
s'agit d'un type tiers que je n'ai pas écrit. En fait, peu importe que l'auteur deDuck
n'ait pas écrit debark
fonction - je peux la fournir après coup quand je dis le langage quiDuck
satisfaitBarkable
:Cela signifie que les
Duck
s peuvent aboyer, et leur fonction d'aboiement est implémentée en frappant le canard avant de le faire charlatan. Avec cela à l'écart, nous pouvons faire appelmakeItBark
à des canards.Standard ML
etOCaml
sont encore plus flexibles dans la mesure où vous pouvez satisfaire la même classe de type de plusieurs manières. Dans ces langues , je peux dire que les entiers peuvent être commandés en utilisant la commande classique, puis demi - tour et dire qu'ils sont également commandable par divisibilité (par exemple10 > 5
parce que 10 est divisible par 5). Dans Haskell, vous ne pouvez instancier une classe de type qu'une seule fois. (Cela permet de savoir Haskell automatiquement qu'il est correct d'appelerbark
sur un canard, en SML ou OCaml , vous devez être explicite sur laquellebark
la fonction que vous voulez, car il pourrait y avoir plus d'un.)Concision
Bien sûr, il y a des différences syntaxiques. Le code Python que vous avez présenté est beaucoup plus concis que l'équivalent Java que j'ai écrit. Dans la pratique, cette concision est une grande partie de l'attrait des langages typés dynamiquement. Mais l'inférence de type vous permet d'écrire du code tout aussi concis dans les langages à typage statique, en vous évitant d'avoir à écrire explicitement les types de chaque variable. Un langage de type statique peut également fournir un support natif pour le typage dynamique, supprimant la verbosité de toutes les manipulations de transtypage et de mappage (par exemple, les C #
dynamic
).Programmes corrects mais mal typés
Pour être juste, la frappe statique exclut nécessairement certains programmes qui sont techniquement corrects même si le vérificateur de type ne peut pas le vérifier. Par exemple:
La plupart des langages de type statique rejetteraient cette
if
déclaration, même si la branche else ne se produira jamais. Dans la pratique, il semble que personne n'utilise ce type de code - quelque chose de trop intelligent pour le vérificateur de type incitera probablement les futurs responsables de votre code à vous maudire, ainsi que vos proches. Exemple: quelqu'un a réussi à traduire 4 projets Python open source en Haskell, ce qui signifie qu'ils ne faisaient rien qu'un bon langage typé statiquement ne pouvait pas compiler. De plus, le compilateur a trouvé quelques bogues liés au type que les tests unitaires ne détectaient pas.L'argument le plus fort que j'ai vu pour le typage dynamique est les macros de Lisp, car elles vous permettent d'étendre arbitrairement la syntaxe du langage. Cependant, Typed Racket est un dialecte de Lisp de type statique qui a des macros, il semble donc que la frappe statique et les macros ne s'excluent pas mutuellement, bien que peut-être plus difficile à implémenter simultanément.
Pommes et oranges
Enfin, n'oubliez pas qu'il existe de plus grandes différences dans les langues que simplement leur système de type. Avant Java 8, faire n'importe quel type de programmation fonctionnelle en Java était pratiquement impossible; un lambda simple nécessiterait 4 lignes de code de classe anonyme standard. Java ne prend pas non plus en charge les littéraux de collection (par exemple
[1, 2, 3]
). Il peut également y avoir des différences dans la qualité et la disponibilité des outils (IDE, débogueurs), des bibliothèques et du support communautaire. Lorsque quelqu'un prétend être plus productif en Python ou Ruby qu'en Java, cette disparité de fonctionnalité doit être prise en compte. Il y a une différence entre comparer les langues avec toutes les batteries incluses , les cœurs de langue et les systèmes de type .la source
C'est une question difficile et assez subjective. (Et votre question peut être fermée en fonction de l'opinion, mais cela ne signifie pas que c'est une mauvaise question - au contraire, même penser à de telles questions en méta-langage est un bon signe - ce n'est tout simplement pas bien adapté au format Q&A de ce forum.)
Voici mon point de vue: le but des langages de haut niveau est de restreindre ce qu'un programmeur peut faire avec l'ordinateur. Cela est surprenant pour beaucoup de gens, car ils pensent que le but est de donner aux utilisateurs plus de puissance et de faire plus . Mais comme tout ce que vous écrivez en Prolog, C ++ ou List est finalement exécuté en tant que code machine, il est en fait impossible de donner au programmeur plus de puissance que le langage d'assemblage ne le fournit déjà.
Le but d'un langage de haut niveau est d' aider le programmeur à mieux comprendre le code qu'il a lui-même créé et à le rendre plus efficace pour faire la même chose. Un nom de sous-programme est plus facile à retenir qu'une adresse hexadécimale. Un compteur d'arguments automatique est plus facile à utiliser qu'une séquence d'appels ici, vous devez obtenir le nombre d'arguments exactement par vous-même, sans aide. Un système de types va plus loin et limite le type d'arguments que vous pouvez fournir à un endroit donné.
C'est là que la perception des gens diffère. Certaines personnes (j'en fais partie) pensent que tant que votre routine de vérification de mot de passe attendra de toute façon exactement deux arguments, et toujours une chaîne suivie d'un identifiant numérique, il est utile de le déclarer dans le code et d'être automatiquement rappelé si vous oubliez plus tard de suivre cette règle. L'externalisation d'une telle comptabilité à petite échelle vers le compilateur permet de libérer votre esprit pour des problèmes de niveau supérieur et vous permet de mieux concevoir et architecturer votre système. Par conséquent, les systèmes de type sont une victoire nette: ils laissent l'ordinateur faire ce qu'il est bon et les humains font ce qu'ils sont bons.
D'autres voient tout à fait différemment. Ils n'aiment pas qu'on leur dise quoi faire. Ils n'aiment pas l'effort supplémentaire de départ pour décider de la déclaration de type et la taper. Ils préfèrent un style de programmation exploratoire où vous écrivez le code d'entreprise réel sans avoir de plan qui vous dirait exactement quels types et arguments utiliser. Et pour le style de programmation qu'ils utilisent, cela peut être tout à fait vrai.
Je simplifie excessivement ici, bien sûr. La vérification de type n'est pas strictement liée à des déclarations de type explicites; il existe également une inférence de type. La programmation avec des routines qui prennent en fait des arguments de types différents permet des choses assez différentes et très puissantes qui seraient autrement impossibles, c'est juste que beaucoup de gens ne sont pas suffisamment attentifs et cohérents pour utiliser une telle latitude avec succès.
En fin de compte, le fait que ces langages différents soient à la fois très populaires et ne montrent aucun signe de disparition montre que les gens ont une programmation très différente. Je pense que les fonctionnalités du langage de programmation sont largement liées aux facteurs humains - ce qui soutient mieux le processus de prise de décision humaine - et tant que les gens travailleront très différemment, le marché fournira des solutions très différentes simultanément.
la source
Le code écrit à l'aide de langages dynamiques n'est pas couplé à un système de type statique. Par conséquent, ce manque de couplage est un avantage par rapport aux systèmes de type statique pauvres / inadéquats (bien qu'il puisse s'agir d'un lavage ou d'un inconvénient par rapport à un grand système de type statique).
De plus, pour un langage dynamique, un système de type statique n'a pas besoin d'être conçu, implémenté, testé et maintenu. Cela pourrait rendre l'implémentation plus simple par rapport à un langage avec un système de type statique.
la source