Фразы типа «статическая типизация» и «динамическая типизация» часто встречаются, и люди, как правило, используют слегка разные определения, поэтому давайте начнем с пояснения того, что мы имеем в виду.
Рассмотрим язык со статическими типами, которые проверяются во время компиляции. Но допустим, что ошибка типа генерирует только нефатальное предупреждение, а во время выполнения все типизируется по типу утки. Эти статические типы предназначены только для удобства программиста и не влияют на codegen. Это показывает, что статическая типизация сама по себе не накладывает никаких ограничений и не является взаимоисключающей с динамической типизацией. (Objective-C очень похож на это.)
Но большинство систем статического типа не ведут себя таким образом. Существует два общих свойства систем статического типа, которые могут накладывать ограничения:
Компилятор может отклонить программу, содержащую ошибку статического типа.
Это ограничение, потому что многие типобезопасные программы обязательно содержат статическую ошибку типа.
Например, у меня есть скрипт Python, который должен запускаться как Python 2 и Python 3. Некоторые функции изменили свои типы параметров между Python 2 и 3, поэтому у меня есть такой код:
if sys.version_info[0] == 2:
wfile.write(txt)
else:
wfile.write(bytes(txt, 'utf-8'))
Средство проверки статического типа Python 2 будет отклонять код Python 3 (и наоборот), даже если он никогда не будет выполнен. Моя типобезопасная программа содержит статическую ошибку типа.
В качестве другого примера рассмотрим программу для Mac, которая хочет работать на OS X 10.6, но использовать преимущества новых функций в 10.7. Методы 10.7 могут существовать или не существовать во время выполнения, и я, программист, могу их обнаружить. Средство проверки статического типа вынуждено либо отклонить мою программу, чтобы обеспечить безопасность типов, либо принять программу вместе с возможностью создания ошибки типа (функция отсутствует) во время выполнения.
Проверка статического типа предполагает, что среда выполнения адекватно описывается информацией времени компиляции. Но предсказывать будущее опасно!
Вот еще одно ограничение:
Компилятор может генерировать код, который предполагает, что тип среды выполнения является статическим типом.
Предполагая, что статические типы являются «правильными», предоставляет много возможностей для оптимизации, но эти оптимизации могут быть ограничивающими. Хорошим примером являются прокси-объекты, например, удаленное взаимодействие. Скажем, вы хотите иметь локальный прокси-объект, который перенаправляет вызовы методов к реальному объекту в другом процессе. Было бы хорошо, если бы прокси был универсальным (чтобы он мог маскироваться под любой объект) и прозрачным (чтобы существующий код не знал, что он разговаривает с прокси). Но для этого компилятор не может сгенерировать код, который предполагает, что статические типы являются правильными, например, путем статически встроенных вызовов методов, потому что это не удастся, если объект на самом деле является прокси.
Примеры такого удаленного взаимодействия в действии включают NSXPCConnection ObjC или TransparentProxy C # (реализация которого потребовала нескольких пессимизаций во время выполнения - см. Здесь для обсуждения).
Когда codegen не зависит от статических типов, и у вас есть такие возможности, как пересылка сообщений, вы можете делать много интересных вещей с прокси-объектами, отладкой и т. Д.
Вот пример некоторых вещей, которые вы можете сделать, если вам не требуется выполнять проверку типов. Ограничения накладываются не статическими типами, а принудительной статической проверкой типов.