Vedo che ci sono già diverse risposte eccellenti. Alcuni dei quali ripeterò, ma a volte vuoi solo mettere le cose con parole tue. Commenterò alcuni esempi del C ++ perché è il linguaggio con cui ho più familiarità.
Ciò che è necessario non è mai poco saggio. L'inferenza del tipo è necessaria per rendere pratiche le funzionalità di altre lingue. In C ++ è possibile avere tipi indicibili.
struct {
double x, y;
} p0 = { 0.0, 0.0 };
// there is no name for the type of p0
auto p1 = p0;
C ++ 11 ha aggiunto lambda che sono anche indicibili.
auto sq = [](int x) {
return x * x;
};
// there is no name for the type of sq
L'inferenza del tipo è anche alla base dei modelli.
template <class x_t>
auto sq(x_t const& x)
{
return x * x;
}
// x_t is not known until it is inferred from an expression
sq(2); // x_t is int
sq(2.0); // x_t is double
Ma le tue domande erano "perché, programmatore, dovrei dedurre il tipo delle mie variabili quando leggo il codice? Non è più veloce per chiunque leggere il tipo piuttosto che pensare che tipo c'è?"
L'inferenza del tipo rimuove la ridondanza. Quando si tratta di leggere il codice, a volte può essere più veloce e più semplice avere informazioni ridondanti nel codice, ma la ridondanza può oscurare le informazioni utili . Per esempio:
std::vector<int> v;
std::vector<int>::iterator i = v.begin();
Non ci vuole molta familiarità con la libreria standard per un programmatore C ++ per identificare che io sono un iteratore, i = v.begin()
quindi la dichiarazione esplicita del tipo ha un valore limitato. Per la sua presenza oscura i dettagli che sono più importanti (come quelli che i
indicano l'inizio del vettore). La bella risposta di @amon fornisce un esempio ancora migliore di verbosità che oscura dettagli importanti. Al contrario, l'uso dell'inferenza di tipo dà maggiore risalto ai dettagli importanti.
std::vector<int> v;
auto i = v.begin();
Sebbene la lettura del codice sia importante, non è sufficiente, ad un certo punto dovrai interrompere la lettura e iniziare a scrivere un nuovo codice. La ridondanza nel codice rende la modifica del codice più lenta e più difficile. Ad esempio, supponiamo che io abbia il seguente frammento di codice:
std::vector<int> v;
std::vector<int>::iterator i = v.begin();
Nel caso in cui ho bisogno di cambiare il tipo di valore del vettore per raddoppiare la modifica del codice in:
std::vector<double> v;
std::vector<double>::iterator i = v.begin();
In questo caso, devo modificare il codice in due punti. Contrasto con l'inferenza del tipo in cui il codice originale è:
std::vector<int> v;
auto i = v.begin();
E il codice modificato:
std::vector<double> v;
auto i = v.begin();
Nota che ora devo solo cambiare una riga di codice. Estrapolarlo a un programma di grandi dimensioni e l'inferenza dei tipi può propagare le modifiche ai tipi molto più rapidamente di quanto sia possibile con un editor.
La ridondanza nel codice crea la possibilità di bug. Ogni volta che il codice dipende da due informazioni che vengono mantenute equivalenti, esiste la possibilità di errore. Ad esempio, c'è un'incongruenza tra i due tipi in questa affermazione che probabilmente non è prevista:
int pi = 3.14159;
La ridondanza rende più difficile discernere l'intenzione. In alcuni casi l'inferenza del tipo può essere più facile da leggere e comprendere perché è più semplice della specifica esplicita del tipo. Considera il frammento di codice:
int y = sq(x);
Nel caso in cui sq(x)
restituisca un int
, non è ovvio se y
sia un int
perché è il tipo restituito sq(x)
o perché si adatta alle istruzioni che usano y
. Se cambio altro codice in modo tale che sq(x)
non ritorni più int
, da quella riga è incerto se il tipo di y
debba essere aggiornato. Contrasto con lo stesso codice ma utilizzando l'inferenza del tipo:
auto y = sq(x);
In questo l'intento è chiaro, y
deve essere dello stesso tipo restituito da sq(x)
. Quando il codice cambia il tipo di ritorno di sq(x)
, il tipo di y
modifica si adatta automaticamente.
In C ++ c'è un secondo motivo per cui l'esempio sopra è più semplice con l'inferenza di tipo, l'inferenza di tipo non può introdurre una conversione di tipo implicita. Se il tipo restituito sq(x)
non è int
, il compilatore inserisce silenziosamente una conversione implicita in int
. Se il tipo restituito sq(x)
è un tipo complesso che definisce operator int()
, questa chiamata di funzione nascosta può essere arbitrariamente complessa.