Hängt die Syntax von Programmiersprachen von ihrer Implementierung ab?

12

Meine Frage mag zwar völlig irrelevant sein, aber ich habe ein Muster zwischen den meisten Programmiersprachen und ihren offiziellen Implementierungen festgestellt.

Interpretierte (byteinterpretierte?) Sprachen wie Python, Lua usw. haben normalerweise eine extrem nachgiebige und einfache Syntax und sind im Allgemeinen typenlos oder erfordern vom Entwickler nicht, Variablentypen explizit in den Quellcode zu schreiben.

Kompilierte Sprachen wie C, C ++, Pascal usw. haben normalerweise eine strenge Syntax, haben im Allgemeinen Typen und erfordern meist mehr Code / Entwicklungszeit

Sprachen, deren offizielle Implementierungen wie Java / C # JIT-kompiliert sind, sind in der Regel ein einzigartiger Kompromiss zwischen den beiden oben genannten und bieten einige der besten Funktionen von beiden.

Einige der moderneren kompilierten Programmiersprachen wie D und Vala (und die GNU GJC-Implementierung von Java) bilden möglicherweise eine Ausnahme von dieser Regel und ähneln der Syntax und den Funktionen von JIT-kompilierten Sprachen wie Java und C #.

Meine erste Frage ist, ist das wirklich relevant? Oder ist dies nur ein Zufall, dass die meisten interpretierten Sprachen eine einfache Syntax haben, JIT-kompilierte Sprachen eine moderate Syntax und Funktionen usw.

Zweitens, wenn dies kein Zufall ist, warum ist es dann so? Wie zum Beispiel, können einige Funktionen nur in einer Programmiersprache implementiert werden, wenn Sie sie beispielsweise JIT-kompilieren?

ApprenticeHacker
quelle
@ YannisRizos sorry, es ist kein Zitat. Ich wollte es nur hervorheben. Ich werde es bearbeiten.
ApprenticeHacker
1
Cool, ich dachte, es war kein Zitat, aber es könnte dazu führen, dass die Antwortenden es für ein Zitat hielten und nicht versuchten, es zu widerlegen (oder blindlings damit einverstanden zu sein) ... Ich habe ähnliche Muster bemerkt, aber leider kein gutes Antworten.
Yannis
@ R.MartinhoFernandes sorry, mir war das nicht bewusst. Ich werde es (wieder) bearbeiten.
ApprenticeHacker
4
Perl wird dynamisch für benutzerdefinierte Typen typisiert, statisch in Bezug auf die Unterscheidung von Arrays, Hashes, Skalaren und Subroutinen und stark typisiert über use strict, interpreted und JIT compiliert (natürlich nicht zur gleichen Zeit) ... Immer wenn jemand es versucht um den Sinn des Sprachdesigns zu verstehen, macht es immer Spaß, sich mit Perl zu beschäftigen ...
yannis
3
Was meinst du mit "milde Syntax" vs. "strenge Syntax"? Sie sind alle formale Sprachen und keiner wird Quellcode mit Syntaxfehlern ausführen.
Nikie

Antworten:

17

Es gibt keinerlei Verbindung zwischen Semantik und Syntax. Homoikonisch kompilierte Sprachen wie Scheme haben eine ziemlich minimalistische Syntax. Kompilierte Metasprachen auf niedriger Ebene wie Forth sind noch einfacher. Einige sehr streng typisierte kompilierte Sprachen basieren auf einer einfachen Syntax (denken Sie an ML, Haskell). OTOH, Python-Syntax ist in Bezug auf eine Reihe von Syntaxregeln sehr schwergewichtig.

Und ja, das Schreiben hat nichts mit Syntax zu tun, es ist auf der semantischen Seite einer Sprache, es sei denn, es ist etwas so Perverses wie C ++, bei dem Sie nicht einmal parsen können, ohne alle Tippinformationen zur Verfügung zu haben.

Ein allgemeiner Trend ist, dass Sprachen, die sich zu lange entwickelt haben und keine Schutzmechanismen gegen Syntaxabweichungen enthalten, sich früher oder später zu syntaktischen Greueln entwickeln.

SK-Logik
quelle
+1 dafür, dass ich "homoikonisch" nachgeschlagen habe ... Und für das subtile Nicken an PHP ...
yannis
1
+1, Sprachen, die sich zu lange entwickelt haben und keine Design-Schutzmaßnahmen enthalten , bezieht sich dies auch auf Delphi / Object-Pascal?
ApprenticeHacker
1
@ThomasEding, du liegst falsch. Dieselbe Semantik kann auf einer Vielzahl von Syntaxstilen implementiert werden, selbst mit einer Sprache ohne Syntax (wie Lisp oder Forth). Dieselbe Syntax kann mit einer Vielzahl unterschiedlicher Semantiken verwendet werden - z. B. ist die Syntax von C- und Verilog-Ausdrücken nahezu identisch, die Semantik jedoch dramatisch unterschiedlich.
SK-logic
1
@ SK-logic - Nur weil es komplex und Turing-komplett ist, bedeutet das nicht, dass es nicht zumindest einen sehr großen Teil der Programm-Syntax ausmacht. Das Parsen verschiedener Sprachen ist Turing-komplett, was das Parsen nicht auf magische Weise zu etwas macht, das "nichts mit Syntax zu tun hat". Bei der Syntax geht es nicht um "Geltungsbereich", sondern um Regeln für die Struktur von Anweisungen in einer Sprache - ohne etwas darüber zu sagen, was diese Anweisungen bedeuten. Die Typprüfung und die Typinferenz werden an Syntaxbäumen von Programmen ausgeführt, ohne sie auszuführen. Sie bestimmen Dinge über die Struktur des Programms, ohne etwas darüber zu sagen ...
Jack
1
@Jack, Sie versuchen, die Syntax neu zu definieren. Es gibt keine praktischen Sprachen, die einen Turing-vollständigen Parser benötigen, die meisten sind nur kontextfrei. Und hier sollte die Syntax bleiben. Bitte erweitern Sie diesen (ohnehin schon zu gedehnten) Begriff nirgendwo anders. Und ich habe bereits den Curry-Howard-Isomorphismus erwähnt - es geht um Semantik, weit über die bloßen Korrektheitsregeln hinaus. Ich denke, der Begriff " type checking" ist äußerst kontraproduktiv und sollte nicht verwendet werden. Er ist sehr irreführend und spiegelt nicht die Art der Typsysteme wider.
SK-logic
6

Meistens ist das ein Zufall.

Die Programmiersprachen haben sich im Laufe der Zeit weiterentwickelt und die Technologie von Compilern und Dolmetschern hat sich verbessert. Die Effizienz der zugrunde liegenden Verarbeitung (dh die Kompilierungszeit, der Interpretationsaufwand, die Ausführungszeit usw.) ist ebenfalls weniger wichtig, da die Leistung der Mainstream-Computerplattformen zugenommen hat.

Die Sprachsyntax hat einen Einfluss - Pascal wurde zum Beispiel sehr sorgfältig entworfen, damit ein Compiler mit einem Durchgang verwendet werden kann - dh ein Durchgang über die Quelle und Sie haben einen ausführbaren Maschinencode. Ada hingegen achtete nicht darauf, und Ada-Compiler sind bekanntermaßen schwer zu schreiben - die meisten erfordern mehr als einen Durchgang. (Ein sehr guter Ada-Compiler, den ich vor vielen Jahren verwendet habe, war ein 8-Pass-Compiler. Wie Sie sich vorstellen können, war er sehr langsam.)

Wenn Sie sich alte Sprachen wie Fortran (kompiliert) und BASIC (interpretiert oder kompiliert) ansehen, haben / hatten sie sehr strenge Syntax- und Semantikregeln. [Im Fall von BASIC, das ist nicht Bills altes BASIC, müssen Sie vorher zum Original zurückkehren.]

Bei älteren Dingen wie APL (ein Haufen Spaß) war dies eine Art dynamisches Tippen. Es wurde auch allgemein interpretiert, konnte aber auch kompiliert werden.

Lenient-Syntax ist eine schwierige Sache. Wenn Sie also Dinge haben, die optional sind oder die abgeleitet werden können, bedeutet dies, dass die Sprache über einen ausreichenden Reichtum verfügt, den sie aussortieren könnte. Andererseits hatte BASIC das vor vielen Jahren, als die Anweisung "LET" optional wurde!

Viele der Ideen, die Sie jetzt sehen (z. B. typenloses oder dynamisches Tippen), sind tatsächlich sehr alt - sie tauchen erstmals in den 1970er oder frühen 1980er Jahren auf. Die Art und Weise, wie sie verwendet werden, und die Sprachen, in denen diese Ideen verwendet werden, haben sich geändert und sind gewachsen. Aber im Grunde genommen ist vieles, was neu ist, altes Zeug in neuen Kleidern.

Hier sind einige Beispiele aus meinem Kopf:

  • APL: Dynamische Eingabe. Generell interpretiert. Kam aus den 1960er / 1970er Jahren.
  • BASIC: Starkes oder dynamisches Tippen. Ausgelegt oder übersetzt. 1970er Jahre und viele darüber hinaus.
  • Fortran: starkes Tippen. Kompiliert. 1960er oder früher.
  • Algol68: starkes Tippen. Kompiliert. 1960er Jahre.
  • PL / 1: starkes Tippen. Kompiliert. 1960er Jahre.
  • Pascal: starkes Tippen. Kompiliert. 1970er Jahre. (Aber in den 1980er Jahren gab es P-System-Compiler, die den JIT-Compilern sehr ähnlich waren!)
  • Einige Implementierungen von Fortran und andere von DEC in den frühen Tagen wurden teilweise kompiliert und teilweise interpretiert.
  • Smalltalk: Dynamische Eingabe. Kompiliert zu Bytecode, der interpretiert wird. 1980er Jahre.
  • Prolog: mehr Fremdheit. Funktional. Kompiliert (Turbo Prolog, jemand?). 1980er Jahre.
  • C: starkes (ha ha) Tippen. Kompiliert. 1960er ... heute.
  • Ada: Überstarkes Tippen. Kompiliert. 1980er Jahre.
  • Perl: Dynamische Eingabe. (Starke Syntax). Interpretiert. 1990er Jahre (?).

Ich könnte weitermachen.

  • Nitpickers-Ecke: Viele interpretierte Sprachen werden zum Zeitpunkt des Ladens / Einlesens der Quelle mit einem Token versehen oder "bytekompiliert". Dies erleichtert die spätere Bedienung des Interpreters erheblich. Manchmal können Sie die Byte-kompilierte Version des Codes speichern. Manchmal kannst du nicht. Es ist immer noch interpretiert.

Update: Weil ich nicht klar genug war.

Die Eingabe kann sehr unterschiedlich sein.

Feste statische Typisierung zur Kompilierungszeit ist üblich (z. B. C, Ada, C ++, Fortan usw. usw.). Hier deklarieren Sie eine SACHE eines TYPS und das ist für immer so.

Es ist auch möglich, dynamisch zu tippen, wobei das Ding den ihm zugewiesenen Typ aufnimmt. Zum Beispiel PHP und einige frühe BASIC- und APL-Versionen, bei denen Sie einer Variablen eine Ganzzahl zuweisen und von da an eine Ganzzahl. Wenn Sie ihm später eine Zeichenfolge zugewiesen haben, war dies ein Zeichenfolgentyp. Und so weiter.

Und dann gibt es loses Tippen, zum Beispiel PHP, wo Sie wirklich bizarre Dinge tun können, wie einer Variablen eine numerische Ganzzahl (in Anführungszeichen gesetzt, also eine Zeichenfolge) zuweisen und dann eine Zahl hinzufügen. (zB '5' + 5 würde 10 ergeben). Dies ist das Land der bizarren, aber auch zuweilen sehr sehr nützlichen.

Dies sind jedoch Funktionen, die in einer Sprache erstellt wurden. Die Implementierung macht das einfach möglich.

schnell_nun
quelle
13
Starkes Tippen ist nicht das Gegenstück zu dynamischem Tippen. Es ist das Gegenstück zum schwachen Tippen. Das Gegenstück zur dynamischen Typisierung ist die statische Typisierung: In einem Fall können die Arten von Ausdrücken in einem Programm statisch bekannt sein (dh ohne das Programm auszuführen). In einem anderen Fall können die Typen nur dynamisch erkannt werden (dh das Programm muss ausgeführt werden).
R. Martinho Fernandes
Ja, und beide Varianten von BASIC und APL haben dies bereits Ende der 1970er Jahre getan. APL-Typen sind nicht ganz so, wie wir sie heute verstehen (das sind Dinge wie universell typisierte Ganzzahlen / Gleitkommazahlen, aber sie können auch Vektoren, Zeichenfolgen und mehrdimensionale Matrizen sein).
quick_now
Ein Fortran-Interpreter ist immer noch weit verbreitet (siehe Cernlib und PAW). Und sein Nachkomme ROOT basiert auf einem C ++ - Interpreter.
SK-logic
Um ehrlich zu sein, ist mir nicht ganz klar, wie stark / schwach und statisch / dynamisch das Tippen mit der Syntax zusammenhängt. Aber die Antwortqualität war ziemlich gut, also vermeide ich nur, mich zu äußern. Ich würde Klasse C als "statisch / schwach" tippen (es ist trivial, einen gespeicherten Wert so zu betrachten, als wäre es ein anderer Typ, der möglicherweise einen falschen Wert liefert).
Vatine
@Vatine - Ich würde eigentlich sagen, stark zur Kompilierungszeit, nicht existent zur Laufzeit - wenn Sie es so wollen. Sie können dies mit Hilfe von Zeigern und deren Entsprechung in vielen Sprachen tun. Es ist sogar im klassischen Pascal mit Variantendatensätzen und in Ada mit UNCHECKED_CONVERSION möglich (obwohl schwierig, ist es möglich).
quick_now
2

Ich denke, es ist umgekehrt: Die Implementierung hängt von der Syntax ab. Wenn Ihre Syntax beispielsweise eine Reflektion zulässt, muss die Implementierung eine Laufzeitumgebung bereitstellen, die dies unterstützt.

StackedCrooked
quelle
@IntermediateHacker: aber es ist in Java, also sollte ich großartig sein
sehe
2

Im Allgemeinen stimme ich quick_now darin zu, dass Ihre Beobachtung hauptsächlich ein Ergebnis der Geschichte ist. Das heißt, die zugrunde liegende Überlegung läuft auf so etwas hinaus:

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

(Eigentlich kein Zitat, nur meine eigene Formulierung.) Wenn ich comfortablehier schreibe , beziehe ich mich auf das, was Sie genannt haben best features of both. Genauer gesagt, ich möchte nicht für oder gegen statische / dynamische Typisierung oder strenge / milde Syntax sprechen. Stattdessen ist es wichtig zu sehen, dass der Fokus auf Entwickler gelegt wird und deren Komfort beim Arbeiten mit der Sprache erhöht wird.

Hier sind einige Gründe, die in früheren Antworten nicht erwähnt wurden, die Ihnen einige Ideen geben können, warum Sie diese Dinge beobachten (und die alle auf der Geschichte der Entwicklung von Programmiersprachen basieren):

  • Wir haben heutzutage Hunderte von Programmiersprachen. Wie kann ein neues Publikum erreicht werden, wenn es auftaucht? Dies ist der Hauptgrund, warum neue Sprachen immer versuchen, das Komfortniveau der Entwickler zu erhöhen. Wenn die Sprache die gleiche Leistung wie eine ältere erbringen kann, dies jedoch viel einfacher / eleganter / etc. Vielleicht möchten Sie überlegen, tatsächlich zu wechseln.

  • Die Lernkurve geht damit einher. In der Vergangenheit hatten wir nur wenige Sprachen und es hat sich gelohnt, Zeit zu investieren, um eine zu lernen. Auch wenn das bedeutete, viel Zeit zu investieren. Der Komfort wird wieder erhöht, wenn Sie eine Sprache finden, die Entwickler sehr schnell lernen können. Komplexität jeglicher Art (z. B. komplizierte Syntax) wirkt sich nachteilig aus und wird daher in neueren Sprachen immer weniger.

  • Technologische Fortschritte (hier ein direkter historischer Grund) sind dafür verantwortlich, dass Compiler-Entwickler sich jetzt mehr auf den Entwicklerkomfort konzentrieren können. Am Anfang waren wir froh, überhaupt einen Compiler bauen zu können. Dies implizierte jedoch häufig starke Einschränkungen. Mit zunehmendem technologischen Know-how konnten wir diese Einschränkungen wieder aufheben.

Generell haben Programmiersprachen und Compiler eine ähnliche Entwicklung erlebt wie typische Endbenutzeranwendungen:

  1. Anfangsphase: Es ist eine coole Sache, aber die Spitzentechnologie bringt es kaum dazu, auf Kosten von Komfort / Benutzerfreundlichkeit / Was-nicht zu funktionieren.
  2. Technologische Verbesserung: Wir können diese Dinge robuster, schneller und einfacher bauen.
  3. Der Fokus richtet sich auf den Benutzer: Ähnlich wie bei der Web2.0-Bewegung, bei der das Benutzererlebnis im Mittelpunkt steht, konzentrieren sich neue Programmiersprachen auf die Entwicklerperspektive.
Frank
quelle
(Not a quote really, just my own formulation.)Nun, Sie haben es als Code formatiert und nicht als Blockquote. Ich glaube, niemand hat gedacht, dass es sich um ein Zitat handelt :)
yannis
3
Komfort hängt eindeutig von einem Geschmack ab (der immer ganz subjektiv ist). Die Sprache, mit der ich mich am wohlsten fühle, wurde 1959 entworfen, und ich kann es nicht ertragen, mich mit einigen der Sprachen zu befassen, die in diesem Jahrhundert erschienen sind.
SK-logic
1
Komfort hängt auch vom Zweck ab. Das Ausführen von PHP oder Prolog auf einem 8k-Embedded-Mikro für einen Waschmaschinen-Controller ist möglicherweise "komfortabel" zu programmieren, aber es ist auch verdammt schwierig, es tatsächlich fit zu machen und mit akzeptabler Leistung auszuführen.
quick_now
0

Eine bestimmte Programmiersprache kann oder kann nicht genügend semantische Informationen bereitstellen oder einschränken, damit ein Compiler daraus schließen kann, wie er sie auf ausführbaren Code ohne zusätzliche Laufzeitentscheidungen reduzieren kann ("Welcher Typ ist diese Variable?" Usw.). Einige Sprachen sind explizit dafür vorgesehen Diese Einschränkung ist obligatorisch oder leicht zu bestimmen.

Wenn Compiler intelligenter werden, können sie möglicherweise genügend Informationen erraten oder profilieren, um ausführbaren Code für die wahrscheinlichsten Pfade zu generieren, selbst für Sprachen, die nicht explizit dafür entwickelt wurden, diese Entscheidungen offen zu legen oder einzuschränken.

Für Sprachen, in denen Code (evalString ()) zur Laufzeit erstellt oder eingegeben werden kann (und für andere Dinge, die der Compiler nicht ableiten oder erraten kann), muss möglicherweise ein Interpreter oder JIT-Compiler zur Laufzeit verfügbar sein, auch wenn versucht wird, kompiliere sie.

In der Vergangenheit wurden eine Programmiersprache und ihre Implementierung möglicherweise so weiterentwickelt, dass bestimmte Hardwareeinschränkungen berücksichtigt wurden, z. B. ob der Interpreter in 4 KB oder 16 KB passt oder ob der Compiler möglicherweise in weniger als einer Minute CPU-Zeit fertig ist. Da Maschinen immer schneller werden, ist es möglich geworden, einige zuvor interpretierte Programme so schnell (neu) zu kompilieren, wie der Programmierer die Eingabetaste drücken kann, oder zuvor kompilierten Programmquellcode schneller zu interpretieren, als etwas ältere Hardware optimierte kompilierte ausführbare Dateien ausführen könnte.

hotpaw2
quelle