Il termine "ortogonalità" è un termine per laico per una precisa nozione matematica: i termini della lingua formano un'algebra iniziale (cercalo in Wikipedia).
In pratica significa "c'è una corrispondenza di 1-1 tra sintassi e significato". Questo significa che c'è esattamente un modo per esprimere le cose e, se riesci a mettere un po 'di espressione in un luogo particolare, puoi inserire anche qualsiasi altra espressione.
Un altro modo di pensare "ortogonale" è che la sintassi obbedisce al principio di sostituzione. Ad esempio, se si dispone di un'istruzione con uno slot per un'espressione, è possibile inserire qualsiasi espressione e il risultato è ancora un programma sintatticamente valido. Inoltre, se sostituisci
Voglio sottolineare che "significato" non implica risultato computazionale. Chiaramente, 1 + 2 e 2 + 1 sono entrambi uguali a 3. Tuttavia i termini sono distinti e implicano un calcolo diverso anche se ha lo stesso risultato. Il significato è diverso, così come due algoritmi di ordinamento sono diversi.
Potresti aver sentito parlare di "abstract syntax tree" (AST). La parola "astratto" qui significa precisamente "ortogonale". Tecnicamente la maggior parte degli AST non sono in realtà astratti!
Forse hai sentito parlare del linguaggio di programmazione "C"? La notazione di tipo C non è astratta. Prendere in considerazione:
int f(int);
Quindi ecco una dichiarazione di funzione che restituisce il tipo int
. Il tipo di puntatore a questa funzione è dato da:
int (*)(int)
Nota, non puoi scrivere il tipo di funzione! La notazione di tipo C fa schifo! Non è astratto Non è ortogonale. Ora, supponiamo di voler creare una funzione che accetti il tipo precedente invece di int:
int (*) ( int (*)(int) )
Tutto ok .. ma .. cosa succede se invece vogliamo restituirlo:
int (*)(int) (*) (int)
Woops! Non valido. Consente di aggiungere parens:
(int (*)(int)) (*) (int)
Woops! Neanche questo funziona. Dobbiamo farlo (è l'unico modo!):
typedef int (intintfunc*) (int);
intintfunc (*)(int)
Ora va bene, ma dover usare un typedef qui è brutto. C fa schifo. Non è astratto Non è ortogonale. Ecco come lo fai in ML, che è:
int -> (int -> int)
Condanniamo C al livello di sintassi.
Ok, ora lascia flog C ++. Possiamo correggere la stupidità di cui sopra con i modelli e ottenere una notazione simile a ML (più o meno):
fun<int, int>
fun< fun<int,int>, int>
ma il sistema di tipi effettivo è fondamentalmente imperfetto dai riferimenti: se T
è un tipo, allora T&
è un tipo? La risposta è waffly: al livello di sintassi, se hai un tipo U = T & amp ;, quindi U & è permesso ma significa solo T & amp ;: un riferimento a un riferimento è il riferimento originale. Questo fa schifo! Rompe semanticamente il requisito di unicità. Peggio ancora: T & & non è permesso sintatticamente: questo rompe il principio di sostituzione. Quindi i riferimenti C ++ interrompono l'ortogonalità in due modi diversi, a seconda del tempo di associazione (analisi o analisi del tipo). Se vuoi capire come farlo bene .. non c'è problema con i puntatori!
Quasi nessuna lingua reale è ortogonale. Persino Scheme, che pretende una grande chiarezza di espressione, non lo è. Tuttavia, molte buone lingue possono essere giudicate "ragionevolmente vicine alla caratteristica ortogonale" e questa è una buona raccomandazione per una lingua, applicata sia alla sintassi che alla semantica sottostante.