Ich kenne das Konzept der Orthogonalität, aber gibt es aus Sicht der Programmiersprache eine Möglichkeit, es zu verifizieren / zu beweisen?
Zum Beispiel kann man in C # public
oder static
für eine Methodensignatur verwenden. Sie können eines oder beide verwenden und sie würden sich nicht gegenseitig stören, also sind sie orthogonal zueinander, oder?
Meine Frage ist, wie gehe ich mit den restlichen Funktionen um, insbesondere mit Funktionen, die nicht miteinander zusammenhängen?
Müssen alle Funktionen nebeneinander existieren / gestapelt werden?
Gibt es eine Programmiersprache, die zu 100% orthogonal ist?
c#
.net
programming-languages
language-design
Joan Venge
quelle
quelle
Antworten:
Ich bin nicht sicher, ob Orthogonalität bei Allzwecksprachen höherer Ordnung wie C # als nützliche oder gültige Metrik dienen kann, da sie die Unterscheidung von "Operationen" und "Operanden" erfordert - den kleinen Teilen der Sprache, die nicht einfach sind unterscheidbar in solchen übergeordneten Sprachen wie C #.
Mein Verständnis der Orthogonalität basiert auf der Assembler-Sprache, in der die Orthogonalität des Befehlssatzes einer bestimmten CPU oder eines bestimmten Mikrocontrollers angibt, ob abhängig von den Datentypen Einschränkungen für die von dieser CPU oder diesem Controller ausgeführten Operationen bestehen. In früheren Zeiten war dies wichtig, da nicht jede CPU Operationen mit Bruchzahlen oder Zahlen unterschiedlicher Länge usw. unterstützte.
In dieser Hinsicht würde ich lieber die Orthogonalität der Common Intermediate Language überprüfen, indem ich die Stack Machine-Sprache als Ziel für den C # -Compiler verwende, nicht C # selbst.
Wenn Sie wirklich an der Orthogonalität von C # interessiert sind und ich mich hier nicht irre (für welchen Zweck auch immer), würde ich vorschlagen, nach einigen genetischen Programmieralgorithmen zu suchen . Sie können diese verwenden, um aus den angegebenen Schlüsselwörtern (auch aus den bedeutungslosen) verschiedene Programme zu generieren, und Sie können einfach automatisch prüfen, ob diese kompilierbar sind. Auf diese Weise können Sie automatisch erkennen, welche Elemente der Sprache miteinander kombiniert werden können, und einige Aspekte Ihrer Orthogonalitätsmetrik ableiten.
quelle
Der Begriff "Orthogonalität" ist ein Laienbegriff für einen präzisen mathematischen Begriff: Die Sprachbegriffe bilden eine anfängliche Algebra (siehe Wikipedia).
Es bedeutet im Grunde "es gibt eine 1-1 Entsprechung zwischen Syntax und Bedeutung". Das bedeutet: Es gibt genau eine Möglichkeit, Dinge auszudrücken, und wenn Sie einen Ausdruck an einer bestimmten Stelle platzieren können, können Sie auch einen anderen Ausdruck dort platzieren.
Eine andere Möglichkeit, über "orthogonal" nachzudenken, besteht darin, dass die Syntax dem Substitutionsprinzip folgt. Wenn Sie beispielsweise eine Anweisung mit einem Steckplatz für einen Ausdruck haben, kann jeder Ausdruck dort abgelegt werden, und das Ergebnis ist immer noch ein syntaktisch gültiges Programm. Darüber hinaus, wenn Sie ersetzen
Ich möchte betonen, dass "Bedeutung" kein Rechenergebnis impliziert. Es ist klar, dass 1 + 2 und 2 + 1 beide gleich 3 sind. Die Begriffe sind jedoch unterschiedlich und implizieren eine andere Berechnung, selbst wenn sie das gleiche Ergebnis haben. Die Bedeutung ist unterschiedlich, genauso wie zwei Sortieralgorithmen unterschiedlich sind.
Möglicherweise haben Sie von "Abstract Syntax Tree" (AST) gehört. Das Wort "abstrakt" bedeutet hier genau "orthogonal". Technisch gesehen sind die meisten ASTs nicht abstrakt!
Vielleicht haben Sie von der Programmiersprache "C" gehört? Die Notation vom Typ C ist nicht abstrakt. Erwägen:
Hier ist also eine Funktionsdeklaration, die den Typ zurückgibt
int
. Der Typ eines Zeigers auf diese Funktion ist gegeben durch:Beachten Sie, dass Sie den Typ der Funktion nicht schreiben können! C Typ Notation saugt bigtime! Es ist nicht abstrakt. Es ist nicht orthogonal. Angenommen, wir möchten eine Funktion erstellen, die den obigen Typ anstelle von int akzeptiert:
Alles in Ordnung .. aber .. was ist, wenn wir es stattdessen zurückgeben möchten:
Woops! Ungültig. Fügen wir Parens hinzu:
Woops! Das funktioniert auch nicht. Wir müssen das tun (es ist der einzige Weg!):
Jetzt ist es in Ordnung, aber hier ein typedef verwenden zu müssen, ist schlecht. C saugt. Es ist nicht abstrakt. Es ist nicht orthogonal. So machen Sie das in ML:
Wir verurteilen C auf Syntaxebene.
Ok, jetzt lass uns C ++ auspeitschen. Wir können die Dummheit oben mit Vorlagen beheben und eine ML-ähnliche Notation erhalten (mehr oder weniger):
Das eigentliche Typensystem ist jedoch durch Referenzen grundlegend fehlerhaft: Wenn
T
es sich um einen Typ handelt, handelt es sich dann umT&
einen Typ? Die Antwort ist waffelig: Wenn Sie auf Syntaxebene einen Typ U = T & haben, ist U & zulässig, aber es bedeutet nur T &: Eine Referenz auf eine Referenz ist die ursprüngliche Referenz. Das ist scheiße! Es bricht die Eindeutigkeitsanforderung semantisch. Schlimmer noch: T & & ist syntaktisch nicht zulässig: Dies verstößt gegen das Substitutionsprinzip. Daher brechen C ++ - Referenzen die Orthogonalität je nach Bindungszeit (Parsing oder Typanalyse) auf zwei verschiedene Arten. Wenn Sie verstehen wollen, wie man das richtig macht, gibt es kein Problem mit Zeigern!Fast keine echten Sprachen sind orthogonal. Sogar das Schema, das eine große Klarheit des Ausdrucks vorgibt, ist es nicht. Es kann jedoch beurteilt werden, dass viele gute Sprachen eine "ziemlich nahe an der orthogonalen Merkmalsbasis" haben, und dies ist eine gute Empfehlung für eine Sprache, die sowohl auf die Syntax als auch auf die zugrunde liegende Semantik angewendet wird.
quelle
int (*intintfunc())(int) { ... }
- intintfunc ist eine Funktion, die keine Argumente akzeptiert und einen Zeiger auf eine Funktion zurückgibt, die 1 int-Argument akzeptiert und einen int-Wert zurückgibt.Der Nachweis der Orthogonalität ist negativ. Es bedeutet, dass Sie keine Konstrukte haben, die nicht orthogonal sind, was bedeutet, dass es viel einfacher ist zu beweisen, dass etwas nicht orthogonal ist als es ist.
In der Praxis sprechen die meisten Menschen über die Orthogonalität von Programmiersprachen in Grad, anstatt entweder vollständig orthogonal zu sein oder nicht. Wenn das Wissen, etwas in einem Kontext zu tun, in einen anderen Kontext übersetzt wird und "das tut, was Sie erwarten", wird diese Sprache als orthogonaler bezeichnet. LISP wird als sehr orthogonal angesehen, da alles eine Liste ist, aber ich glaube nicht, dass es aufgrund einiger Redundanzen, die die Verwendung vereinfachen, zu 100% orthogonal ist. C ++ wird als nicht sehr orthogonal angesehen, da es viele kleine "Fallstricke" gibt, bei denen es nicht ganz so funktioniert, wie Sie es sich vorstellen.
quelle
Achtung, ich weiß nichts über dieses Thema.
Ein kurzer Blick auf Wikipedia scheint darauf hinzudeuten, dass Orthogonalität hauptsächlich auf Entwurfsmuster und Systemdesign abzielt. In Bezug auf Programmiersprachen gibt der Eintrag an, dass Befehlssätze orthogonal sind, wenn es für jede mögliche Aktion einen und nur einen Befehl gibt oder vielmehr kein Befehl einen anderen überlappt.
Für C # würde ich mir vorstellen, dass es orthogonal ist, da die meisten Syntaxtricks (
foreach
die mir in den Sinn kommen) einfach Frontends für speziell geformte Versionen des Basiskonstrukts sind (werdenforeach
zufor
Schleifen). Insgesamt unterstützt die Sprache nur wirklich, Dinge auf eine einzige Weise zu tun, obwohl syntaktischer Zucker zusätzliche Möglichkeiten bietet, sie zu tun. Und schließlich wird alles aufMSIL
(oder wie auch immer es heutzutage heißt) kompiliert undMSIL
ist wahrscheinlich orthogonal.Wenn Sie den Vorbehalt machen, dass syntaktisches Zuckermaterial im Wesentlichen ein "Wrapper" ist, um es auf "harte Weise" zu tun, können Sie die verschiedenen Merkmale der Sprache analysieren, Zucker weglassen und feststellen, ob es Konstrukte gibt, die sich wirklich überschneiden. Wenn nicht, könnte ich mir vorstellen, dass Sie die Sprache orthogonal deklarieren könnten.
Meine zwei Cent.
quelle
do...while
verwendet werden, um den gleichen Effekt wie zu erzielenfor
? Ich habe noch nie davon gehört, dass es sich um syntaktischen Zucker handelt.do while
garantiert eine Ausführung einer einzelnen Schleife und überprüft den Zustand nachträglich .for
prüft zuerst die Bedingung und garantiert keine einzige Ausführung.Sie machen weiter, was Sie tun, und zählen alle Kombinationen auf, die funktionieren oder verboten sind.
Das ist alles. Es ist ziemlich schmerzhaft zu tun.
Wenn alle Funktionen in disjunkte Teilmengen unterteilt werden können, die sich nicht gegenseitig stören, sind alle sinnvoll.
Alle Datenstrukturen arbeiten mit allen primitiven Typen. Alle Ausdrucksoperatoren arbeiten mit allen Typen. Dies sind gebräuchliche Definitionen der Orthogonalität. Aber vielleicht möchten Sie mehr (oder weniger)
Manchmal gibt es jedoch Sonderfälle aufgrund von Betriebssystemen oder Legacy-Bibliotheken, die nicht orthogonal sind.
Außerdem sind einige Typen überhaupt nicht sehr anpassungsfähig. Mit Python können Sie beispielsweise zwei Wörterbuchobjekte für die "Bestellung" vergleichen. Aber es gibt fast keine vernünftige Definition von "Ordnen" unter Wörterbüchern. Python definiert eine, aber es ist ziemlich umstritten. Lässt dieser Sonderfall Wörterbücher einen Orthogonalitätstest nicht bestehen?
Wie orthogonal ist "orthogonal genug"? Was müssen Sie sehen, um mit dem Grad der Orthogonalität in Ihrer Sprache zufrieden zu sein ?
quelle
Die Liste der unorthogonalen Merkmale ist in den meisten Programmiersprachen in der Tat lang, z
Das sind nur ein paar, die mir in den Sinn kommen, aber es gibt viele andere und auch in anderen Sprachen.
Es ist schwer sicherzustellen, dass es keine subtilen Interferenzen zwischen Sprachmerkmalen gibt. Wie CAR Hoare in seinem Artikel "Hinweise zum Design von Programmiersprachen" angibt:
Wahrscheinlich besteht ein guter Schritt zur Erhöhung der Orthogonalität darin, Konzepte zu vereinheitlichen (dies geht in Richtung der Antwort von @ karl-bielfeld). Wenn alles ist, sagen wir eine Liste oder ein Objekt, besteht die Möglichkeit, dass es weniger Konflikte gibt. Oder anstatt eine Klasse nachträglich verschachtelt zu haben, machen Sie sie zu einer Kernfunktion.
Die meisten Programmiersprachenpapiere belegen bestimmte Eigenschaften der Sprache (z. B. Typensicherheit) in einer Teilmenge (einem "Kern") der formalisierten Sprache. Hier sollten wir das Gegenteil tun und beweisen, dass alle Funktionen sicher zusammengesetzt sind. Das bedeutet auch, dass man definieren sollte, was es bedeutet, "zu komponieren". Bedeutet es "rennen"? (In diesem Fall ist der obige Link zum Randfall mit dynamischer und statischer Typisierung sicher). Bedeutet es, "sicher" zu sein? Bedeutet es, aus Entwicklersicht vorhersehbar zu sein?
Das alles ist sehr interessant - aber auch sehr herausfordernd.
quelle