Il codice macchina non rende magicamente irrilevante il controllo del tipo. La cosa con molte varietà di codice macchina è che non hanno alcuna comprensione intrinseca dei tipi. Ma questo non significa che non puoi costruire un sistema di tipi su di essi usando le tue convenzioni.
Come esempio banale, potresti decidere che ogni valore è di 16 bit. I primi 8 bit rappresentano il tipo e il secondo 8 bit rappresenta il valore effettivo. Ora hai qualcosa che puoi controllare in fase di esecuzione per verificare che non stai aggiungendo un cavallo alla tua latitudine. Ecco c=b+c
in pseudo-assembly:
enter // function entry
loadw [ax], bx // load 16 bits at [ax] into bx
loadw [ax+2], cx // load 16 bits at [ax+2] into cx
cmp bl, cl // compare the low bytes of bx and cx
jne ERROR // if ^ is not equal, jump to ERROR
addb bh, ch // add the high bytes of bx and cx, store in ch
storw cx, [ax+2] // store cx back in memory
ret // return to caller
ERROR:
// Handle error, print warning, throw exception, etc
Questo è un esempio delle istruzioni che un linguaggio di tipo dinamicamente può compilare fino a (in questo caso, un linguaggio veramente fragile, considera che anche se b
e c
sono uguali tipo, l'aggiunta potrebbe essere un'operazione completamente priva di senso da eseguire su di essi, ad esempio GUID+GUID=huh?
). Ecco cosa può fare una lingua tipizzata staticamente:
enter // function entry
loadb [ax], bh // load 8 bits at [ax] into bh
loadb [ax+1], ch // load 8 bits at [ax+1] into ch
addb bh, ch // add bh and ch, store in ch
storb ch, [ax+1] // store ch back in memory
ret // return to caller
Notare che non c'è cmp
, jne
o gestione degli errori. Perché? Poiché una lingua tipizzata staticamente può dimostrare , senza eseguire il programma, una coppia di tipi non validi non entrerà mai in quella sezione di codice. Pertanto, può tranquillamente scegliere il codice di controllo. E dal momento che non controlla i metadati di tipo extra, può anche lasciarlo fuori, quindi perché carica e memorizza solo byte da 8 bit invece di parole da 16 bit.
Allo stesso modo, il codice macchina non ripulisce magicamente la tua spazzatura per te. Se utilizzi un garbage collector, non scompare solo durante la compilazione, viene tradotto nella lingua di destinazione insieme al resto del tuo programma .
Ma si noti che un garbage collector non è necessariamente meno efficiente delle alternative. malloc()
non è necessariamente deterministico.