La syntaxe des langages de programmation dépend-elle de leur implémentation?

12

Bien que ma question puisse être totalement hors de propos, mais j'ai senti un schéma entre la plupart des langages de programmation et leurs implémentations officielles.

Les langages interprétés ( interprétés en octets?) Comme Python, Lua etc. ont généralement une syntaxe extrêmement clémente et facile et sont généralement sans type ou ne nécessitent pas que le développeur écrive explicitement les types de variables dans le code source;

Les langages compilés comme C, C ++, Pascal, etc. ont généralement une syntaxe stricte, ont généralement des types et nécessitent généralement plus de temps de code / développement

Les langages dont les implémentations officielles sont compilées en JIT comme Java / C # sont généralement un compromis unique entre les deux ci-dessus avec certaines des meilleures fonctionnalités des deux.

Certains des langages de programmation compilés les plus modernes comme D et Vala (et l'implémentation GNU GJC de Java) sont peut-être une exception à cette règle et ressemblent à la syntaxe et aux fonctionnalités des langages compilés JIT comme Java et C #.

Ma première question est la suivante: est-ce vraiment pertinent? Ou est-ce juste une coïncidence si la plupart des langages interprétés ont une syntaxe facile, ceux compilés en JIT ont une syntaxe et des fonctionnalités modérées, etc.

Deuxièmement, si ce n'est pas une coïncidence, pourquoi en est-il ainsi? Comme, par exemple, certaines fonctionnalités ne peuvent-elles être implémentées dans un langage de programmation que si, par exemple, vous le compilez en JIT?

ApprenticeHacker
la source
@YannisRizos désolé, ce n'est pas une citation. Je voulais juste le souligner. Je vais le modifier.
ApprenticeHacker
1
Cool, je pensais que ce n'était pas une citation mais cela pouvait amener les répondants à penser que c'était une et ne pas essayer de la réfuter (ou aveuglément d'accord avec elle) ... J'ai remarqué des modèles similaires mais malheureusement je n'ai pas de bonne répondre.
yannis
@ R.MartinhoFernandes désolé, je n'étais pas au courant de cela. Je vais le modifier (encore).
ApprenticeHacker
4
Perl est typé dynamiquement pour les types définis par l'utilisateur, typé statiquement en ce qui concerne les tableaux, hachages, scalaires et sous-programmes, et fortement typé via l'utilisation stricte, interprétée et compilée JIT (pas en même temps bien sûr) ... Chaque fois que quelqu'un essaie pour donner un sens à la conception du langage, jeter du Perl est toujours amusant ...
yannis
3
Qu'entendez-vous par «syntaxe indulgente» et «syntaxe stricte»? Ce sont tous des langages formels et aucun n'exécutera de code source avec des erreurs de syntaxe.
nikie

Réponses:

17

Il n'y a aucun lien entre la sémantique et la syntaxe. Les langages compilés homoiconiques comme Scheme sont livrés avec une syntaxe assez minimaliste. Les méta-langages compilés de bas niveau comme Forth sont encore plus simples que cela. Certains langages compilés très strictement typés sont construits sur une syntaxe triviale (pensez ML, Haskell). OTOH, la syntaxe Python est très lourde, en termes d'un certain nombre de règles de syntaxe.

Et oui, la frappe n'a rien à voir avec la syntaxe, c'est du côté sémantique d'un langage, à moins que ce soit quelque chose d'aussi pervers que C ++, où vous ne pouvez même pas analyser sans avoir toutes les informations de frappe disponibles.

Une tendance générale est que les langages qui ont évolué trop longtemps et qui ne contenaient aucune garantie de conception contre les écarts de syntaxe évolueraient tôt ou tard en abominations syntaxiques.

SK-logic
la source
+1 pour m'avoir fait chercher "homoiconique" ... Et pour le clin d'œil subtil à PHP ...
yannis
1
+1, langages ayant évolué trop longtemps et ne contenant aucune protection de conception , cela fait-il également référence à Delphi / Object-Pascal?
ApprenticeHacker
1
@ThomasEding, vous vous trompez. La même sémantique peut être implémentée sur une très large gamme de styles de syntaxe, même avec un langage sans syntaxe (comme Lisp ou Forth). La même syntaxe peut être utilisée avec une très grande variété de sémantiques différentes - par exemple, la syntaxe des expressions C et Verilog est presque la même, mais la sémantique est radicalement différente.
SK-logic
1
@ SK-logic - Ce n'est pas parce qu'il est complexe et que Turing-complete n'est pas au moins une très grande partie de la syntaxe du programme. L'analyse de divers langages est complète de Turing, ce qui ne fait pas comme par magie quelque chose qui n'a "rien à voir avec la syntaxe". La syntaxe ne concerne pas la «portée», elle concerne les règles de structure des instructions dans un langage - sans rien dire sur la signification de ces instructions. La vérification de type et l'inférence de type opèrent sur des arbres de syntaxe de programmes sans les exécuter - ils déterminent des choses sur la structure du programme sans rien dire sur ...
Jack
1
@Jack, vous essayez de redéfinir ce qu'est la syntaxe. Il n'y a pas de langages pratiques qui nécessitent un analyseur complet de Turing, la plupart ne sont rien de plus que sans contexte. Et c'est là que la syntaxe doit rester. Veuillez ne pas étendre cette notion (déjà trop étirée) ailleurs. Et j'ai déjà mentionné l'isomorphisme de Curry-Howard - il s'agit de sémantique, bien au-delà des simples règles de correction. Je pense que le terme même " type checking" est extrêmement contre-productif et ne doit pas être utilisé, il est très trompeur, il ne reflète pas la nature des systèmes de types.
SK-logic
6

C'est surtout une coïncidence.

Les langages de programmation ont évolué au fil du temps et la technologie des compilateurs et des interprètes s'est améliorée. L'efficacité du traitement sous-jacent (c'est-à-dire le temps de compilation, le temps d'interprétation, le temps d'exécution, etc.) est également moins importante car les plates-formes informatiques traditionnelles ont gagné en puissance.

La syntaxe du langage n'avoir un impact - par exemple, Pascal a été très soigneusement conçu de sorte qu'il pourrait utiliser un seul compilateur passe - à savoir une passe sur la source et vous avez le code machine excutable. Ada, d'autre part, n'y a pas prêté attention, et les compilateurs Ada sont notoirement difficiles à écrire - la plupart nécessitent plus d'un passage. (Un très bon compilateur Ada que j'ai utilisé il y a de nombreuses années était un compilateur à 8 passes. Comme vous pouvez l'imaginer, il était très lent.)

Si vous regardez des langues anciennes comme Fortran (compilées) et BASIC (interprétées ou compilées), elles ont / avaient une syntaxe et des règles sémantiques très strictes. [Dans le cas de BASIC, ce ne sont pas des anciens factures de BASIC, vous devez revenir avant cela à l'original.]

D'un autre côté, en regardant d'autres choses plus anciennes comme APL (un tas d'amusement), cela avait une sorte de typage dynamique. Il a également été généralement interprété, mais pourrait également être compilé.

La syntaxe indulgente est difficile - si cela signifie que vous avez des choses facultatives ou que vous pouvez en déduire, cela signifie que le langage a une richesse suffisante pour pouvoir être éliminé. Là encore, BASIC a eu cela il y a de nombreuses années lorsque l'instruction "LET" est devenue facultative!

Bon nombre des idées que vous voyez maintenant (par exemple, la frappe sans type ou dynamique) sont en fait très anciennes - apparues pour la première fois dans les années 1970 ou au début des années 1980. La façon dont elles sont utilisées et les langues dans lesquelles ces idées sont utilisées ont changé et se sont développées. Mais fondamentalement, une grande partie de ce qui est nouveau est en fait de vieilles choses habillées de nouveaux vêtements.

Voici quelques exemples du haut de ma tête:

  • APL: typage dynamique. Généralement interprété. Venu des années 60/70.
  • BASIC: typage fort ou dynamique. Interprété ou compilé. 1970 et bien au-delà.
  • Fortran: typage fort. Compilé. Années 1960 ou antérieures.
  • Algol68: typage fort. Compilé. Années 60.
  • PL / 1: typage fort. Compilé. Années 60.
  • Pascal: typage fort. Compilé. Années 1970. (Mais dans les années 1980, il y avait des compilateurs P-System très similaires aux compilateurs JIT!)
  • Certaines implémentations de Fortran et d'autres par DEC dans les premiers jours ont été partiellement compilées et partiellement interprétées.
  • Smalltalk: frappe dynamique. Compilé en bytecode qui est interprété. Années 80.
  • Prolog: plus d'étrangeté. Fonctionnel. Compilé (Turbo Prolog, n'importe qui?). Années 80.
  • C: typage fort (ha ha). Compilé. Des années 60 ... aujourd'hui.
  • Ada: typage ultra-fort. Compilé. Années 80.
  • Perl: typage dynamique. (Syntaxe forte). Interprété. Années 1990 (?).

Je pourrais continuer.

  • Coin Nitpickers: De nombreux langages interprétés sont tokenisés ou "compilés en octets" au moment où la source est chargée / lue. Cela rend l'opération suivante de l'interpréteur beaucoup plus simple. Parfois, vous pouvez enregistrer la version compilée en octets du code. Parfois, vous ne pouvez pas. C'est toujours interprété.

Mise à jour: parce que je n'étais pas assez clair.

La saisie peut varier considérablement.

Le typage statique fixe à la compilation est courant (par exemple, C, Ada, C ++, Fortan, etc.). C'est là que vous déclarez une CHOSE d'un TYPE et c'est ainsi pour toujours.

Il est également possible d'avoir une frappe dynamique, où la chose récupère le type qui lui est assigné. Par exemple, PHP et certains premiers BASIC, et APL, où vous assigneriez un entier à une variable et à partir de ce moment-là c'était un type entier. Si vous lui avez ensuite attribué une chaîne, il s'agissait d'un type de chaîne. Etc.

Et puis il y a un typage lâche, par exemple PHP où vous pouvez faire des choses vraiment bizarres comme assigner un entier numérique (entre guillemets, donc c'est une chaîne) à une variable et ensuite y ajouter un nombre. (par exemple, «5» + 5 donnerait 10). C'est le pays du bizarre, mais aussi parfois du très très utile.

CEPENDANT, ce sont des fonctionnalités conçues dans une langue. L'implémentation rend cela possible.

vite_maintenant
la source
13
La frappe forte n'est pas la contrepartie de la frappe dynamique. C'est la contrepartie d'une frappe faible. La contrepartie du typage dynamique est le typage statique: dans l'un, les types d'expressions dans un programme peuvent être connus statiquement (c'est-à-dire sans exécuter le programme); dans un autre, les types ne peuvent être connus que dynamiquement (c'est-à-dire que le programme doit être exécuté).
R. Martinho Fernandes
Oui et les deux variantes de BASIC et APL le faisaient à la fin des années 1970. Les types APL ne sont pas tout à fait tels que nous les comprenons aujourd'hui (étant des choses comme des nombres entiers / flottants universellement typés, mais pourraient également être des vecteurs, des chaînes et des matrices multidimensionnelles).
quick_now
Un interprète Fortran est encore largement utilisé (voir Cernlib et PAW). Et son descendant, ROOT, est construit sur un interpréteur C ++.
SK-logic
Pour être honnête, je ne suis pas tout à fait clair à quel point le typage fort / faible et statique / dynamique est lié à la syntaxe. Mais la qualité de la réponse était plutôt bonne, donc j'évite simplement les votes positifs. Je classerais le typage C comme "statique / faible" (il est trivial de regarder une valeur stockée comme s'il s'agissait d'un autre type, peut-être de se tromper).
2011 Vatine
@Vatine - Je dirais en fait fort au moment de la compilation, inexistant au moment de l'exécution - si vous le souhaitez. Vous pouvez le faire en utilisant des pointeurs et leur équivalent dans de nombreuses langues. C'est même possible en pascal classique en utilisant des enregistrements de variantes, et en Ada en utilisant UNCHECKED_CONVERSION (bien que difficile, c'est possible).
quick_now
2

Je pense que c'est l'inverse: la mise en œuvre dépend de la syntaxe. Par exemple, si votre syntaxe permet la réflexion, l'implémentation doit fournir un runtime qui prend en charge cela.

StackedCrooked
la source
@IntermediateHacker: mais il est en Java, donc je devrais être génial
sehe
2

Je suis généralement d'accord avec quick_now en ce que votre observation est principalement le résultat de l'histoire. Cela dit, le raisonnement sous-jacent se résume à quelque chose comme ceci:

The more modern a language is, the more comfortable it should be to use.

(Pas vraiment une citation, juste ma propre formulation.) Quand j'écris comfortableici, je me réfère à ce que vous avez appelé best features of both. Plus précisément, je ne veux pas parler pour ou contre le typage statique / dynamique ou la syntaxe stricte / indulgente. Au lieu de cela, il est important de voir l'accent mis sur les développeurs et d'augmenter leur niveau de confort lors de l'utilisation du langage.

Voici quelques raisons, qui n'ont pas été mentionnées dans les réponses précédentes, qui peuvent vous donner quelques idées pour lesquelles vous observez ces choses (et qui sont toutes basées sur l'histoire du développement de la programmation de la langue):

  • Nous avons des centaines de langages de programmation de nos jours. Lorsqu'un nouveau arrive, comment peut-il trouver un large public? C'est la raison principale pour laquelle les nouveaux langages essaient toujours d'augmenter le niveau de confort des développeurs. Si la langue peut faire la même chose qu'une ancienne, mais peut le faire beaucoup plus facilement / plus simplement / plus élégamment / etc. vous voudrez peut-être envisager de changer réellement.

  • La courbe d'apprentissage va de pair avec cela. Dans le passé, nous avions peu de langues et investir du temps pour en apprendre une en valait la peine. Même si cela signifiait investir beaucoup de temps. Le confort est encore augmenté, si vous venez avec un langage que les développeurs peuvent apprendre très rapidement. La complexité de toute sorte (par exemple, syntaxe complexe impliquée) est préjudiciable à cela et, par conséquent, est de plus en plus réduite dans les langues plus récentes.

  • Les progrès technologiques (une raison historique directe ici) sont responsables du fait que les constructeurs de compilateurs peuvent désormais se concentrer davantage sur le confort des développeurs. Au début, nous étions heureux de pouvoir construire un compilateur. Cependant, cela impliquait souvent de lourdes restrictions. À mesure que le savoir-faire technologique augmentait, nous avons pu à nouveau lever ces restrictions.

Ainsi, en général, les langages de programmation et les compilateurs ont connu un développement similaire à celui des applications d'utilisateur final typiques:

  1. Étape initiale: c'est une bonne chose à avoir, mais la technologie de pointe la fait à peine fonctionner au détriment du confort / de l'utilisabilité / quoi.
  2. Amélioration technologique: nous pouvons construire ces choses de manière plus robuste, plus rapide et plus facile.
  3. L'attention se tourne vers l'utilisateur: de la même manière que le mouvement Web2.0 axé sur l'expérience utilisateur, les nouveaux langages de programmation se concentrent sur la perspective des développeurs.
Franc
la source
(Not a quote really, just my own formulation.)Eh bien, vous l'avez formaté en code, pas en bloc, donc je ne pense pas que quiconque ait pensé que c'était une citation :)
yannis
3
Le confort dépend clairement d'un goût (qui est toujours entièrement subjectif). La langue avec laquelle je suis le plus à l'aise a été conçue en 1959, et je ne supporte pas de traiter certaines des langues qui sont apparues au cours de ce siècle.
SK-logic
1
Le confort dépend également du but. Exécuter PHP ou Prolog sur un micro intégré 8k pour un contrôleur de machine à laver peut être "confortable" à programmer, mais aussi sacrément difficile de le faire s'adapter et de fonctionner avec des performances acceptables.
quick_now
0

Un langage de programmation donné peut ou non exposer ou contraindre suffisamment d'informations sémantiques pour qu'un compilateur puisse déduire comment le réduire en code exécutable sans décisions d'exécution supplémentaires ("de quel type est cette variable?", Etc.) Certains langages sont explicitement conçus pour faire cette contrainte est obligatoire ou facile à déterminer.

Au fur et à mesure que les compilateurs deviennent plus intelligents, ils pourraient être en mesure de deviner ou de profiler suffisamment d'informations pour générer du code exécutable pour les chemins les plus probables, même pour les langages qui n'ont pas été explicitement conçus pour exposer ou limiter ces décisions.

Cependant, les langages dans lesquels le code (evalString ()) peut être créé ou entré au moment de l'exécution (et d'autres choses que le compilateur ne peut pas déduire ou deviner) peuvent nécessiter qu'un interprète ou un compilateur JIT soit disponible au moment de l'exécution, même avec des tentatives de pré- compilez-les.

Dans le passé, un langage de programmation et son implémentation pouvaient avoir évolué de manière à s'adapter à certaines contraintes matérielles, par exemple si l'interpréteur pouvait tenir en 4k ou 16k, ou si le compilateur pouvait terminer en moins d'une minute de temps CPU. Au fur et à mesure que les machines s'accélèrent, il est devenu possible de (re) compiler certains programmes précédemment interprétés aussi vite que le programmeur peut appuyer sur la touche de retour, ou d'interpréter le code source du programme précédemment compilé plus rapidement qu'un matériel légèrement plus ancien ne pouvait exécuter des exécutables compilés optimisés.

hotpaw2
la source