Я думаю, вы смешиваете, когда типы проверяются с тем, как они проверяются. Время выполнения не обязательно слабое.
Основным преимуществом статических типов является именно то, что вы говорите: они исчерпывающие. Вы можете быть уверены, что все сайты вызовов соответствуют типу, просто позволяя компилятору делать свое дело.
Основным ограничением статических типов является то, что они ограничены в ограничениях, которые они могут выражать. Это зависит от языка: большинство языков имеют относительно простые системы типов (c, java), а другие - с чрезвычайно мощными системами типов (haskell, cayenne).
Из-за этого ограничения сами по себе не являются достаточными. Например, в java-типах более или менее ограничены проверки совпадения имен типов. Это означает, что значение любого проверяемого ограничения должно быть закодировано в какой-либо схеме именования, отсюда и множество косвенных указателей и общей схемы, общей для Java-кода. C ++ немного лучше в том, что шаблоны позволяют немного больше выразительности, но не приближаются к тому, что вы можете делать с зависимыми типами. Я не уверен, каковы недостатки более мощных систем типов, хотя очевидно, что некоторые или более людей будут использовать их в промышленности.
Даже если вы используете статическую типизацию, скорее всего, она недостаточно выразительна, чтобы проверять все, что вам нужно, поэтому вам также придется писать тесты. Вопрос о том, экономит ли вам статическая типография больше усилий, чем требуется, - это спор, который бушует целую вечность, и я не думаю, что он может дать простой ответ для всех ситуаций.
Что касается вашего второго вопроса:
Как мы можем безопасно перефакторизовать язык ввода во время выполнения?
Ответ - тесты. Ваши тесты должны охватывать все случаи, которые имеют значение. Инструменты могут помочь вам оценить, насколько исчерпывающими являются ваши тесты. Инструменты проверки покрытия позволяют узнать, охвачены ли тесты строки кода или нет. Инструменты тестовой мутации (шут, хекл) могут дать вам знать, если ваши тесты логически неполны. Приемочные тесты позволяют узнать, что написанное соответствует требованиям, и, наконец, регрессионные тесты и тесты производительности гарантируют, что каждая новая версия продукта поддерживает качество последней.
Одной из замечательных особенностей правильного тестирования на месте по сравнению со сложными указаниями типов является то, что отладка становится намного проще. При запуске тестов вы получаете конкретные ошибочные утверждения внутри тестов, которые четко выражают то, что они делают, а не тупые операторские сообщения об ошибках (например, ошибки шаблона c ++).
Независимо от того, какие инструменты вы используете: написание кода, в котором вы уверены, потребует усилий. Скорее всего, это потребует написания множества тестов. Если штраф за ошибки составляет очень , например, для аэрокосмического или медицинского программного обеспечения, вам может потребоваться использовать формальные математические методы для доказательства поведения вашего программного обеспечения, что делает такую разработку чрезвычайно дорогой.