Pourquoi la saisie dynamic est-elle si souvent associée aux langues interprétées?

Questions simples: je fais beaucoup de programmation (professionnellement et personnellement) dans des langages compilés comme C ++ / Java et dans des langages interprétés comme Python / Javascript. Je trouve personnellement que mon code est presque toujours plus robuste lorsque je programme dans des langages statiques. Cependant, presque tous les langages interprétés que je rencontre utilisent le typage dynamic (PHP, Perl, Python, etc.). Je sais pourquoi les langages compilés utilisent le typage statique (la plupart du temps), mais je n’arrive pas à comprendre l’aversion pour le typage statique dans la conception du langage interprété.

Pourquoi la déconnexion raide? Cela fait-il partie de la nature des langages interprétés? OOP?

    Question interessante. BTW, je suis l’auteur / mainteneur de phc (compilateur pour PHP), et je fais mon doctorat sur les compilateurs pour les langages dynamics, alors j’espère que je peux vous donner quelques idées.

    Je pense qu’il y a une hypothèse erronée ici. Les auteurs de PHP, Perl, Python, Ruby, Lua, etc. n’ont pas conçu de «langages interprétés», ils ont conçu des langages dynamics et les ont mis en œuvre à l’aide d’interprètes. Ils l’ont fait parce que les interprètes sont beaucoup plus faciles à écrire que les compilateurs.

    La première implémentation de Java a été interprétée et c’est un langage typé statiquement. Il existe des interpréteurs pour les langages statiques: Haskell et OCaml ont tous deux des interprètes, et il y avait un interpréteur populaire pour C, mais c’était il y a longtemps. Ils sont populaires car ils permettent un REPL , ce qui peut faciliter le développement.

    Cela dit, comme vous vous en doutez, il existe une aversion pour le typage statique dans la communauté des langages dynamics. Ils croient que les systèmes de type statique fournis par C, C ++ et Java sont verbeux et ne valent pas la peine. Je pense que je suis d’accord avec cela dans une certaine mesure. La programmation en Python est bien plus amusante que C ++.

    Répondre aux points des autres:

    • Dlamblin dit : “Je n’ai jamais vraiment senti qu’il y avait quelque chose de spécial à propos de la compilation et de l’interprétation qui suggéraient un typage dynamic plutôt que statique.” Eh bien, vous vous trompez vraiment là-bas. La compilation de langages dynamics est très difficile. Il y a surtout l’instruction eval à prendre en compte, qui est largement utilisée dans Javascript et Ruby. phc comstack PHP à l’avance, mais nous avons toujours besoin d’un interpréteur d’exécution pour gérer eval s. eval ne peut pas non plus être analysé de manière statique dans un compilateur optimisé, bien qu’il y ait une technique géniale si vous n’avez pas besoin de solidité.

    • Pour répondre à Andrew Hare : vous pouvez bien sûr effectuer une parsing statique dans un interpréteur et trouver des erreurs avant l’ exécution, ce qui est exactement ce que fait le ghci d’Haskell. J’espère que le style d’interprète utilisé dans les langages fonctionnels l’exige. Dlamblin a bien sûr raison de dire que l’parsing ne fait pas partie de l’interprétation.

    • La réponse d’Andrew Hare se fonde sur l’hypothèse erronée des questionneurs et, de la même manière, les choses se passent mal. Cependant, il soulève une question intéressante: “Comment l’parsing statique des langages dynamics est-elle difficile?”. Très très dur En gros, vous obtiendrez un doctorat pour décrire son fonctionnement, ce que je fais exactement. Voir aussi le point précédent.

    • La réponse la plus correcte à ce jour est celle d’ Ivo Wetzel . Cependant, les points qu’il décrit peuvent être traités au moment de l’exécution dans un compilateur, et de nombreux compilateurs existent pour Lisp et Scheme qui ont ce type de liaison dynamic. Mais, oui, c’est difficile.

    Les langages interprétés utilisent le typage dynamic car il n’y a pas d’étape de compilation pour effectuer l’parsing statique. Les langages compilés effectuent une parsing statique au moment de la compilation, ce qui signifie que toute erreur de type est signalée au développeur au fur et à mesure de son fonctionnement.

    Il est plus facile de comprendre si vous considérez qu’un langage de type statique a un compilateur qui applique des règles de type en dehors du contexte d’exécution. Les langues interprétées ne sont jamais analysées de manière statique, de sorte que les règles de type doivent être appliquées par l’interprète dans le contexte de l’exécution.

    Je pense que c’est à cause de la nature des langages interprétés, ils veulent être dynamics, donc vous pouvez changer les choses à l’exécution. Pour cette raison, le compilateur ne sait jamais exactement quel est l’état du programme après l’exécution de la ligne de code suivante.

    Imaginez le scénario suivant (en Python):

     import random foo = 1 def doSomeStuffWithFoo(): global foo foo = random.randint(0, 1) def asign(): global foo if foo == 1: return 20 else: return "Test" def toBeStaticallyAnalyzed(): myValue = asign() # A "Comstackr" may throw an error here because foo == 0, but at runtime foo maybe 1, so the comstackr would be wrong with its assumption myValue += 20 doSomeStuffWithFoo() # Foo could be 1 or 0 now... or 4 ;) toBeStaticallyAnalyzed() 

    Comme vous pouvez l’espérer, un compilateur n’aurait aucun sens dans cette situation. En fait, il pourrait vous avertir de la possibilité que “myValue” soit autre chose qu’un numéro. Mais en JavaScript, cela échouerait car si “myValue” est une chaîne, 20 serait convertie implicitement en une chaîne, donc aucune erreur ne se produirait. Donc, vous pourriez recevoir des milliers d’avertissements inutiles partout, et je ne pense pas que ce soit l’intention d’un compilateur.

    La flexibilité vient toujours avec un prix, vous devez examiner votre programme plus en profondeur, ou le programmer avec plus de soin, en d’autres termes, vous êtes le COMPILATEUR dans des situations comme celles-ci.

    Donc, votre solution en tant que compilateur? – Fixez le avec un “try: except” 🙂

    Compilateurs + types statiques = code machine efficace
    Comstackrs + Dynamic types = code machine inefficace

    Considérons le pseudo-code suivant:

     function foo(a, b) { return a+b } 

    Un langage statique sera capable de savoir (par déclaration ou par inférence) que a et b sont des entiers, et seront compilés jusqu’à

     %reg = addi a,b 

    ou quelque chose de similaire, de toute façon.

    Un compilateur pour un langage dynamic devrait émettre du code pour
    1. Vérifiez leurs types de a et b
    2. traiter chaque cas ou combinaison de cas

     %reg1 = typeof a beq %reg1, int, a_int_case beq %reg1, float, a_float_case beq %reg1, ssortingng, a_ssortingng_case label a_int_case %reg1 = typeof b beq %reg1, int, a_int_b_int_case beq %reg1, float, a_int_b_float_case beq %reg1, ssortingng, a_int_b_ssortingng_case label a_int_b_int_case %out = addi a,b goto done label a_int_b_float_case %tmp = mkfloat a %out = addf %tmp,b goto done ... Etc. I can't finish 

    Bien que vous puissiez générer du code machine plus intelligent que cela, vous ne pourriez pas aider à générer beaucoup de code, ce qui rend la compilation moins rentable pour un langage dynamic.

    Comme les interpréteurs sont beaucoup plus faciles à écrire et que la compilation ne vous fait pas beaucoup de bien, pourquoi ne pas écrire un interprète?

    (Les compilateurs juste-à-temps ont en fait des informations de type et peuvent être compilés jusqu’à la seule instruction. Ils ont en réalité plus d’informations que les systèmes de type statique et peuvent théoriquement faire encore mieux. Tous les assembleurs sont simulés; pourrait fonctionner sur une vraie machine est purement fortuite.)