Aufbauend auf Charles 'Antwort besteht die Hauptschwierigkeit in der Theorie der Programmiersprachen darin, dass der natürliche Begriff der Äquivalenz von Programmen weder in der einfachsten mathematischen Semantik, die Sie geben können, noch im zugrunde liegenden Maschinenmodell eine strikte Gleichheit darstellt. Betrachten Sie beispielsweise das folgende Stück Java-ähnlichen Codes:
Object x = new Object();
Object y = new Object();
... some more code ...
Also erstellt dieses Programm ein Objekt und benennt es mit x, erstellt dann ein zweites Objekt mit dem Namen y und führt dann weiteren Code aus. Angenommen, ein Programmierer beschließt, die Zuordnungsreihenfolge dieser beiden Objekte umzudrehen:
Object y = new Object();
Object x = new Object();
... some more code ...
Stellen Sie nun die Frage: Ändert dieses Refactoring das Verhalten des Programms? Zum einen werden auf der zugrunde liegenden Maschine x und y in den beiden Programmläufen an unterschiedlichen Stellen zugeordnet. In diesem Sinne verhält sich das Programm also anders.
In einer Java-ähnlichen Sprache können Sie Referenzen jedoch nur auf Gleichheit und nicht auf Ordnung testen. Dies ist also ein Unterschied, den der "etwas mehr Code" nicht feststellen kann . Infolgedessen erwarten die meisten Programmierer, dass die Umkehrung der Reihenfolge keinen Einfluss auf die endgültige Antwort hat, und die meisten Compiler-Autoren erwarten, dass sie auf dieser Basis Nachbestellungen und Optimierungen vornehmen können. (Auf der anderen Seite, in einem C-ähnlicher Sprache, Sie können Zeiger für die Bestellung vergleichen, indem man sich auf ganze Zahlen zuerst Gießen und so diese Neuanordnung tut nicht unbedingt beobachtbares Verhalten erhalten.)
Eine der zentralen Fragen der Semantik ist die Beantwortung der Frage, wann zwei Programme beobachtbar gleichwertig sind. Da unser Begriff der Beobachtung von den Merkmalen der Programmiersprache abhängt, ergibt sich eine Definition wie "zwei Programme sind äquivalent, wenn kein Client-Programm unterschiedliche Antworten auf der Grundlage des Empfangs dieser Programme als Eingaben berechnen kann". Die Quantifizierung aller Client-Programme macht diese Frage schwierig - es scheint, als müssten Sie etwas über alle möglichen Client-Programme sagen, um etwas über zwei bestimmte Codeteile zu sagen.
Der Trick bei der Denotationssemantik besteht darin, eine mathematische Interpretation zu geben, mit der Sie diese universelle Quantifizierung vermeiden können. Sie sagen, dass die Bedeutung eines Codeteils ein mathematischer Wert ist, und vergleichen sie, indem Sie prüfen, ob sie mathematisch gleich oder gleich sind nicht. Dies ist lokal (dh kompositorisch) und beinhaltet keine Quantifizierung über alle möglichen Kunden. (Sie müssen zeigen, dass die Denotationssemantik eine kontextbezogene Äquivalenz impliziert, damit sie stichhaltig ist. Wenn sie vollständig ist - wenn die Denotationsgleichheit genau der kontextbezogenen Äquivalenz entspricht, ist die Semantik "vollständig abstrakt".)
Dies bedeutet jedoch, dass Sie sicherstellen müssen, dass die Denotationssemantik diese Äquivalenzen validiert. Wenn Sie also in diesem Beispiel eine Denotationssemantik für diese Java-ähnliche Sprache angeben möchten, müssen Sie sicherstellen, dass beim Aufruf von new nicht nur ein Heap erstellt und ein neuer Heap mit dem neu erstellten Objekt zurückgegeben wird, sondern auch die Bedeutung des Programms ist unter allen Permutationen des Eingabeheaps gleich. Dies kann recht komplexe mathematische Strukturen beinhalten (zB in diesem Fall in einer Kategorie arbeiten, die sicherstellt, dass alles Modulo einer geeigneten Permutationsgruppe funktioniert).