Veo que ya hay una serie de buenas respuestas. Algunas de las cuales repetiré, pero a veces solo quieres poner las cosas en tus propias palabras. Comentaré con algunos ejemplos de C ++ porque ese es el lenguaje con el que estoy más familiarizado.
Lo que es necesario nunca es imprudente. La inferencia de tipos es necesaria para hacer prácticas otras características del lenguaje. En C ++ es posible tener tipos indescriptibles.
struct {
double x, y;
} p0 = { 0.0, 0.0 };
// there is no name for the type of p0
auto p1 = p0;
C ++ 11 agregó lambdas que también son indescriptibles.
auto sq = [](int x) {
return x * x;
};
// there is no name for the type of sq
La inferencia de tipos también sustenta las plantillas.
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
Pero sus preguntas fueron "¿por qué yo, el programador, querría inferir el tipo de mis variables cuando leo el código? ¿No es más rápido para alguien leer el tipo que pensar qué tipo hay?"
La inferencia de tipos elimina la redundancia. Cuando se trata de leer el código, a veces puede ser más rápido y fácil tener información redundante en el código, pero la redundancia puede eclipsar la información útil . Por ejemplo:
std::vector<int> v;
std::vector<int>::iterator i = v.begin();
No hace falta mucha familiaridad con la biblioteca estándar para que un programador de C ++ identifique que soy un iterador, por i = v.begin()
lo que la declaración de tipo explícita es de valor limitado. Por su presencia, oculta detalles que son más importantes (como los que i
apuntan al comienzo del vector). La buena respuesta de @amon proporciona un ejemplo aún mejor de verbosidad que eclipsa detalles importantes. En contraste, el uso de la inferencia de tipos le da mayor importancia a los detalles importantes.
std::vector<int> v;
auto i = v.begin();
Si bien la lectura del código es importante, no es suficiente, en algún momento tendrá que dejar de leer y comenzar a escribir código nuevo. La redundancia en el código hace que la modificación del código sea más lenta y difícil. Por ejemplo, supongamos que tengo el siguiente fragmento de código:
std::vector<int> v;
std::vector<int>::iterator i = v.begin();
En el caso de que necesite cambiar el tipo de valor del vector para cambiar el código dos veces a:
std::vector<double> v;
std::vector<double>::iterator i = v.begin();
En este caso, tengo que modificar el código en dos lugares. Contraste con la inferencia de tipos donde el código original es:
std::vector<int> v;
auto i = v.begin();
Y el código modificado:
std::vector<double> v;
auto i = v.begin();
Tenga en cuenta que ahora solo tengo que cambiar una línea de código. Extrapolar esto a un programa grande y la inferencia de tipos puede propagar los cambios a los tipos mucho más rápido que con un editor.
La redundancia en el código crea la posibilidad de errores. Cada vez que su código depende de que dos datos se mantengan equivalentes, existe la posibilidad de error. Por ejemplo, hay una inconsistencia entre los dos tipos en esta declaración que probablemente no se pretende:
int pi = 3.14159;
La redundancia hace que la intención sea más difícil de discernir. En algunos casos, la inferencia de tipos puede ser más fácil de leer y comprender porque es más simple que la especificación de tipo explícita. Considere el fragmento de código:
int y = sq(x);
En el caso de que sq(x)
devuelva un int
, no es obvio si y
es un int
porque es el tipo de retorno de sq(x)
o porque se ajusta a las declaraciones que utilizan y
. Si cambio otro código de modo que sq(x)
ya no regrese int
, es incierto de esa línea solo si el tipo de y
debe actualizarse. Contraste con el mismo código pero usando inferencia de tipos:
auto y = sq(x);
En esto, la intención es clara, y
debe ser del mismo tipo que devuelto por sq(x)
. Cuando el código cambia el tipo de retorno de sq(x)
, el tipo de y
cambios para que coincida automáticamente.
En C ++ hay una segunda razón por la cual el ejemplo anterior es más simple con la inferencia de tipos, la inferencia de tipos no puede introducir la conversión de tipos implícita. Si el tipo de retorno de sq(x)
no es int
, el compilador con silenciosamente inserta una conversión implícita a int
. Si el tipo de retorno de sq(x)
es un tipo complejo de tipo que define operator int()
, esta llamada de función oculta puede ser arbitrariamente compleja.