Semantik steht für Bedeutung oder Sinn.
Während
1 | int i = 4
|
2 | i += 4;
|
3 | i -= 4;
|
oder
syntaktisch korrekt sind, macht es mehr oder weniger Sinn (auch wenn im
letzten Fall gcc vermutlich den Sinn anzweifelt).
Oder
1 | int f(int x, int m, int c) {
|
2 | return m * x + c;
|
3 | }
|
ist syntaktisch gesprochen eine Funktion mit drei Argumentent, die
arithmetisch verrechnet werden. Semantisch ist es eine lineare Funktion.
Es ist sogar eine Funktion im mathematischen Sinn bzw. des funktionalen
Paradigmas, da es bei gleichen Eingabewerten immer das gleiche Ergebnis
erzeugt.
Ein Ziel kann es sein, mit syntaktischen Elementen Semantik zu
verdeutlichen bzw. den Compiler bei der semantischen Intention ("was
will ich damit ausdrücken?") helfen zu lassen:
1 | int x;
|
2 | {
|
3 | int i = 4;
|
4 | x = 5 + i;
|
5 | }
|
Das syntaktische Element des anonymen Blocks bedeutet hier, dass der
Scope von i reduziert wird. Die Intention bestand somit darin, dass i
nur für die Berechnung von x herangezogen wird, und darüber hinaus nicht
verwendet werden soll. Das wirkt in C ungewohnt oder gekünstelt (ich
nutze es ziemlich oft).
In funktionalen Programmiersprachen (Lisp, Haskell, F# oder Scala) wird
sehr viel Wert darauf gelegt, dass aus dem Zusammenspiel von Syntax und
der Bibliothek die Semantik direkt ablesbar ist (höhere semantische
"Ausdruckstärke"). Das ist m. E. in imperativen Sprachen wie Java/C++
schwieriger. Das letzte Beispiel in Scala sähe so aus:
1 | val x = {
|
2 | val i = 4
|
3 | 5 + i
|
4 | }
|
und x ist in diesem Fall "const".
"Design patterns" geben somit gewissen Vorgehensweisen einen
(semantischen) Namen, sozusagen zur Vereinfachung der
Kommunikation/Dokumentation der Intention/Bedeutung.
Ein Gradmesser für die semantische Ausdrücksstärke könnte die Anzahl der
Kommentare sein, die man benötigt, um aus der Syntax die Semantik
abzuleiten. Immer wieder nett:
1 | PORTA = 0x4e; // Aktiviere pins ....
|
besonders dann, wenn der Kommentar nicht mehr zum Code passt.