Я вижу, что уже есть много хороших ответов. Некоторые из них я повторю, но иногда вы просто хотите выразить это своими словами. Я прокомментирую некоторые примеры из C ++, потому что это язык, с которым я наиболее знаком.
То, что необходимо, никогда не бывает неразумным. Вывод типа необходим, чтобы сделать другие языковые особенности практичными. В C ++ возможно иметь невыразимые типы.
struct {
double x, y;
} p0 = { 0.0, 0.0 };
// there is no name for the type of p0
auto p1 = p0;
В C ++ 11 добавлены лямбда-выражения, которые также невыразимы.
auto sq = [](int x) {
return x * x;
};
// there is no name for the type of sq
Вывод типа также поддерживает шаблоны.
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
Но ваши вопросы были такими: «Почему я, программист, хочу выводить тип моих переменных, когда я читаю код? Разве не быстрее, если кто-то просто прочитает тип, чем подумает, какой тип существует?»
Вывод типа удаляет избыточность. Когда дело доходит до чтения кода, иногда бывает проще и быстрее иметь избыточную информацию в коде, но избыточность может затмить полезную информацию . Например:
std::vector<int> v;
std::vector<int>::iterator i = v.begin();
Программисту C ++ не нужно много знакомиться со стандартной библиотекой, чтобы определить, что я являюсь итератором, i = v.begin()
поэтому явное объявление типа имеет ограниченную ценность. Своим присутствием он скрывает детали, которые являются более важными (например, это i
указывает на начало вектора). Прекрасный ответ @amon дает еще лучший пример многословия, затеняя важные детали. Напротив, использование вывода типа делает более заметными важные детали.
std::vector<int> v;
auto i = v.begin();
Хотя чтение кода важно, но его недостаточно, в какой-то момент вам придется прекратить чтение и начать писать новый код. Избыточность в коде делает изменение кода медленнее и сложнее. Например, скажем, у меня есть следующий фрагмент кода:
std::vector<int> v;
std::vector<int>::iterator i = v.begin();
В случае, если мне нужно изменить тип значения вектора на двойное, изменив код на:
std::vector<double> v;
std::vector<double>::iterator i = v.begin();
В этом случае я должен изменить код в двух местах. Сравните с выводом типа, где исходный код:
std::vector<int> v;
auto i = v.begin();
И модифицированный код:
std::vector<double> v;
auto i = v.begin();
Обратите внимание, что теперь мне нужно изменить только одну строку кода. Экстраполируйте это на большую программу, и вывод типа может распространять изменения на типы намного быстрее, чем вы можете с помощью редактора.
Избыточность в коде создает возможность ошибок. Всякий раз, когда ваш код зависит от двух частей информации, сохраняющих эквивалентность, существует вероятность ошибки. Например, есть несоответствие между этими двумя типами в этом утверждении, которое, вероятно, не предназначено:
int pi = 3.14159;
Избыточность затрудняет распознавание намерений. В некоторых случаях вывод типа может быть легче читать и понимать, потому что он проще, чем явная спецификация типа. Рассмотрим фрагмент кода:
int y = sq(x);
В случае, когда sq(x)
возвращается int
, неясно, y
является ли int
это типом, sq(x)
потому что это тип возвращаемого значения или потому, что он соответствует операторам, которые используют y
. Если я изменю другой код таким образом, чтобы он sq(x)
больше не возвращался int
, из этой строки неясно, y
следует ли обновлять тип . Сравните с тем же кодом, но используя вывод типа:
auto y = sq(x);
В этом намерение ясно, y
должен быть того же типа, который был возвращен sq(x)
. Когда код меняет тип возвращаемого значения sq(x)
, тип y
изменений автоматически совпадает.
В C ++ есть вторая причина, по которой приведенный выше пример проще с выводом типа: вывод типа не может вводить неявное преобразование типа. Если тип возвращаемого значения sq(x)
- нет int
, компилятор с молча вставляет неявное преобразование в int
. Если возвращаемый тип sq(x)
является сложным типом, который определяет operator int()
, этот скрытый вызов функции может быть произвольно сложным.