А теперь несколько самых распространенных заблуждений о системах статической и динамической типизации:
1. Статическая типизация подразумевает объявления типов
Дело в том, что Java, Pascal, C++ и C не просто языки со статической типизацией — это языки с явным объявлением типов. Многим не нравится тратить кучу времени на описание типов функций и переменных, и они не любят статически типизированные языки именно по этой причине. Это зря, потому как, скажем в ML и Haskell типы объявлять в большинстве случаев не нужно, при этом они являются на 100% языками с развитой системой статической проверки типов. Вот и в C# (и C++) сейчас видны подвижки в сторону включения в язык неявного вывода типов в некоторых случаях.
2. Динамическая типизация = "слабая" типизация
Это заблуждение происходит от того, что люди, привыкшие к C/C++ и программирующие на динамических языках используют их, скажем так, не в полной мере. Они боятся рантайм ошибок, помня, что такие ошибки на C могут стоить нескольких дней ковыряния в коде с отладчиком — и поэтому начинают добавлять кучу ненужных комментариев, пытаться всячески явно отслеживать информацию о типах значений, когда это совсем необязательно.
Они совершают кучу ненужных телодвижений — и конечно же, после всего этого, программирование на динамических языках им кажется сложнее. Это все равно что купить новую машину, но не ездить на ней быстрее велосипеда: по лесным тропинкам не поездишь, бензин жрет — велосипед круче в сто раз.
А все дело в том, что в динамических языках сам подход другой, главным образом это быстрое написание кода и интенсивное тестирование потом. В динамических языках есть отличные средства для быстрого и четкого отлова рантайм ошибок, с диагностикой, которая покажет вам, почему именно ошибка произошла (см. идеологию "Let it crash" в Erlang.)
3. Статическая типизация не сочетается с итеративными/agile процессами разработки, заставляет разрабатывать архитектуру целиком и полностью до кодирования, и вообще предполагает водопадную модель.
Некоторые статически типизированные языки и правда устроены так, чтобы стимулировать определенный подход к процессу разработки. Пример этого — требование объявлять все переменные заранее в Паскале, заголовочные файлы в C++ (хотя там это отчасти продиктовано практическими соображениями).
Подобные ограничения частью — пережитки прошлого, когда на стиль программирования серьезно влияли различные ограничения компилятора, частью — осознанные решения, принятые разработчиками языка, чтобы заставить программиста следовать определенной идеологии. Однако, все это не имеет отношения к статической типизации, ни в одной серьезной работе по теории типов нету ничего ни о "разделении интерфейса и реализации", ни об необходимости объявлять переменные заранее, ни о прочих оргвопросах.
4. Языки с динамической типизацией не предоставляют средств для поиска багов на этапе разработки
Распространенный аргумент против динамических языков — это то, что ошибки вылезают у пользователя, а не у разработчика. Однако, в реальности это происходит очень редко, так что аргумент хреновый — программы на динамических языках в среднем содержат не особенно больше ошибок чем на языках вроде C++ и Java. Если это вообще можно измерить.
5. Статическая типизация ведет к более объемным исходникам
Ну данное заблуждение происходит опять таки из распространенного мнения что в статических языках приходится явно объявлять все типы.
Красивый пример из Haskell: есть функция lookup, которая ищет в Map (ассоциативном массиве) значение по ключу. Тип у нее такой:
lookup :: (Monad m, Ord k) => k -> Map k a -> m a
Если кто с хаскелем не знаком — у функции два аргумента, ключ типа k и ассоциативный массив с типом ключа k и типом значений a. Возвращает функция значение типа a, завернутое в монаду m.
Вроде все просто, но что она должна делать если ключа такого нет? Возвращать специальное "пустое" значение? Прерывать вычисления и переходить к обработчику ошибок? Или вообще завершать выполнение программы? Фишка в том что функция эта может делать все вышеперечисленное, вот как это выглядит:
case (lookup bobBarker employees) of
Nothing -> hire bobBarker
Just salary -> pay bobBarker salary
Как Хаскель узнал что мы хотим именно первый вариант, получать значение Nothing в случае ошибки? Он увидел что мы сравниваем результат с Nothing, и вывел соответствующий конкретный тип для монады m. Если б мы не написали этого куска кода, обрабатывающего ошибки сразу, а воткнули бы обработчик ошибок где-нибудь несколькими уровнями выше по стеку — Хаскель тоже правильно вывел бы тип, и можно было б вызывать lookup несколько раз, не заботясь о том, что ключа может не оказаться.
Оригинал: "What To Know Before Debating Type Systems"