до 20, однако, применяя их, вам не удастся добиться того, чтобы значение
Закрепленные объявления нужны для того, чтобы на практике избегать лавинного дублирования кода. Объявляя y: like x, вы получаете гарантию того, что
Закрепленные объявления - это особый случай последнего требуемого нам языкового механизма - ковариантности, подробное обсуждение которого нам предстоит позже.
При разработке программных систем на деле необходимо еще одно свойство, присущее самой среде разработки - быстрая, возрастающая (fast incremental) перекомпиляция. Когда вы пишите или модифицируете систему, хотелось бы как можно скорее увидеть эффект изменений. При статической типизации вы должны дать компилятору время на перепроверку типов. Традиционные подпрограммы компиляции требуют повторной трансляции всей системы (и ее сборки), и этот процесс может быть мучительно долгим, особенно с переходом к системам большого масштаба. Это явление стало аргументом в пользу интерпретирующих систем, таких как ранние среды Lisp или Smalltalk, запускавшие систему практически без обработки, не выполняя проверку типов. Сейчас этот аргумент позабыт. Хороший современный компилятор определяет, как изменился код с момента последней компиляции, и обрабатывает лишь найденные изменения.
'Типизирована ли кроха'?
Наша цель - строгая статическая типизация. Именно поэтому мы и должны избегать любых лазеек в нашей 'игре по правилам', по крайней мере, точно их идентифицировать, если они существуют.
Самой распространенной лазейкой в статически типизированных языках является наличие преобразований, меняющих тип сущности. В C и производных от него языках их называют 'приведением типа' или кастингом (cast). Запись
Подобные механизмы обходят ограничения проверки типов. Приведение широко распространено при программировании на языке C, включая диалект ANSI C. Даже в языке C++ приведение типов, хотя и не столь частое, остается привычным и, возможно, необходимым делом.
Придерживаться правил статической типизации не так просто, если в любой момент их можно обойти путем приведения.
Далее будем полагать, что система типов является строгой и не допускает приведения типа.
Возможно, вы заметили, что попытка присваивания - неотъемлемый компонент реалистичной системы типов - напоминает приведение. Однако есть существенное отличие: попытка присваивания выполняет проверку, действительно ли текущий тип соответствует заданному типу, - это безопасно, а иногда и необходимо. |
Типизация и связывание
Хотя как читатель этой книги вы наверняка отличите статическую типизацию от статического связывания, есть люди, которым подобное не под силу. Отчасти это может быть связано с влиянием языка Smalltalk, отстаивающего динамический подход к обеим задачам и способного сформировать неверное представление, будто они имеют одинаковое решение. (Мы же в своей книге утверждаем, что для создания надежных и гибких программ желательно объединить статическую типизацию и динамическое связывание.)
Как типизация, так и связывание имеют дело с семантикой Базисной Конструкции
Типизация и связывание
[x]. Вопрос о типизации: когда мы должны точно знать, что во время выполнения появится операция, соответствующая
[x]. Вопрос о связывании: когда мы должны знать, какую операцию инициирует данный вызов?
Типизация отвечает на вопрос о наличии как минимум одной операции, связывание отвечает за выбор нужной.
В рамках объектного подхода:
[x]. проблема, возникающая при типизации, связана с полиморфизмом: поскольку
[x]. проблема связывания вызвана повторными объявлениями: так как класс может менять наследуемые компоненты, то могут найтись две или более операции, претендующие на то, чтобы представлять
Обе задачи могут быть решены как динамически, так и статически. В существующих языках представлены все четыре варианта решения.
[x]. Ряд необъектных языков, скажем, Pascal и Ada, реализуют как статическую типизацию, так и статическое связывание. Каждая сущность представляет объекты только одного типа, заданного статически. Тем самым обеспечивается надежность решения, платой за которую является его гибкость.
[x]. Smalltalk и другие ОО-языки содержат средства динамического связывания и динамической типизации. При этом предпочтение отдается гибкости в ущерб надежности языка.
[x]. Отдельные необъектные языки поддерживают динамическую типизацию и статическое связывание. Среди них - языки ассемблера и ряд языков сценариев (scripting languages).
[x]. Идеи статической типизации и динамического связывания воплощены в нотации, предложенной в этой книге.
Отметим своеобразие языка C++, поддерживающего статическую типизацию, хотя и не строгую ввиду наличия приведения типов, статическое связывание (по умолчанию), динамическое связывание при явном указании виртуальных (virtual) объявлений.
Причина выбора статической типизации и динамического связывания очевидна. Первый вопрос: 'Когда мы будем знать о существовании компонентов?' - предполагает статический ответ: 'Чем раньше, тем лучше', что означает: во время компиляции. Второй вопрос: 'Какой из компонентов использовать?' предполагает динамический ответ: 'тот, который нужен', - соответствующий динамическому типу объекта, определяемому во время выполнения. Это единственно приемлемое решение, если статическое и динамическое связывание дает различные результаты.