Я всегда рассматривал это скорее для удобства, чем для того, чтобы алгоритм мог или не может быть выражен вообще. Если бы я действительно хотел запускать программы, подобные придуманной Митчеллом, я просто написал бы соответствующий симулятор Turing Machine на своем статически типизированном языке.
Уловка со статической системой типов состоит в том, чтобы предложить правильные виды гибкости только для случаев, когда гибкость позволяет вам писать код, который легче поддерживать.
Вот несколько примеров методов структурирования программ, которые иногда считаются более простыми в динамическом управлении, чем в статически типизированных языках.
Дженерики и Контейнеры
В статически типизированных языках до ML (ок. 1973 г.) и CLU (ок. 1974 г.) было несложно создать красно-черное дерево строк, красно-черное дерево целых чисел, красно-черное дерево с плавающей точкой или красно-черное дерево элементов определенного типа Foo
. Однако было трудно (возможно, невозможно) создать единственную реализацию красно-черного дерева, которая была бы статически проверена и могла обрабатывать любой из этих типов данных. Обойти эту проблему можно было следующим образом: (1) полностью вырваться из системы типов (например, используяvoid *
в C), (2) написать себе какой-то макрос препроцессор, а затем написать макросы, которые производят код для каждого конкретного типа, который вы хотите, или (3) использовать подход Lisp / Smalltalk (и Java) для проверки типа извлеченного Объект динамически
ML и CLU ввели понятие, соответственно, предполагаемых и явно объявленных (статических) параметризованных типов, которые позволяют вам писать универсальные, статически типизированные, контейнерные типы.
Подтип Полиморфизм
В статически типизированных языках до Simula67 (ок. 1967 г.) и Hope (ок. 1977 г.) было невозможно одновременно выполнить динамическую диспетчеризацию и статически проверить, что вы охватили случай для каждого подтипа. Многие языки имели некоторую форму меченых союзов , но это было обязанностью программиста , чтобы убедиться , что их case
или switch
заявления, или их таблицы прыгать, покрыли каждый возможный тег.
Языки, следующие модели Simula (C ++, Java, C #, Eiffel), предоставляют абстрактные классы с подклассами, где компилятор может проверить, что каждый подкласс реализовал все методы, объявленные родительским классом. Языки, следующие модели Hope (все варианты ML, от SML / NJ до Haskell), имеют алгебраические подтипы, где компилятор может проверить, что каждый typecase
оператор охватывает все подтипы.
Patching от Monkey и Аспектно-ориентированное программирование
Системы динамического типа значительно упрощают различные методы создания прототипов. В языках, где типы представлены хеш-картами из строк в функции (например, Python, Javascript, Ruby), довольно легко глобально изменить поведение каждого модуля, который зависит от конкретного типа, просто путем динамического изменения хеш-карты, представляющей тип.
Хотя существуют очевидные способы, с помощью которых исправление обезьяны может усложнить поддержку программ, существуют также способы, с помощью которых они могут быть использованы для «добра», а не «зла». В частности, в аспектно-ориентированном программировании можно использовать методы, аналогичные мартышко-патчированию, для таких вещей, как изменение типа файла для указания на виртуализированную файловую систему, позволяющее создавать инфраструктуры для модульного тестирования для «бесплатных», или модифицировать простые типы исключений, чтобы они печатать сообщения журнала каждый раз, когда они перехвачены для лучшей отладки.
В отличие от Generics и Subtype Polymorphism, где ключевые идеи статической проверки были доступны в 1970-х годах, статическая проверка для аспектно-ориентированного программирования является (я думаю) активной областью исследований. Я мало что знаю об этом, за исключением того, что с 2001 года существует язык AspectJ .