Т. Пратт, М. Зелковиц - Языки программирования - разработка и реализация (4-е издание_ 2002) (1160801), страница 55
Текст из файла (страница 55)
Основным преимуществом динамического определения типов является гибкость программы: объявления типов отсутствуют, и тип объекта данных, связанного с некоторым именем, может меняться по мере необходимости в процессе выполнения программы. Программист, таким образом, лишается большей части забот, связанных с типами данных, Но, с другой стороны, динамический контроль типов имеет песколъко существенных недостатков.
1. Затрудняется отлцдкз программы (то есть становится трудно удалить все ошибки, связанные с типами аргументов). Поскольку динамический контроль происходит во время выполнения операции, для некоторых операций типы аргументов мо~ ут остаться непроверенными (такая ситуация возникает, если для конкретных входных данных эти операции относятся к невыполняемым ветвям программы).
Вообще говоря, в процессе тестирования программы невозможно проверить все сс ветви. Все непроверенные ветви могут содержать ошибки, связанные с типами аргументов, 2. Динамический контроль типов подразумевает, что вся информация о типах должна сохранятся на всем протяжении работы программы, что требует дополнительных объемов памяти, иногда весьма счщественных. 5.Е Свойства типов и объектов 197 3. динамический контроль типов должен быть, как правило, реализован посрсдством программного моделирования, поскольку аппаратная часть компьютера чагце всег о не обеспечивает таких возможностей, Это приводит к замедлению выполнения программы. В большинстве языков предприняты попытки свести на нет или минимизировать динамический контроль типов путем замены его на статический контроль, то есть контроль во время компиляции.
Необходимая для статического контроля информация частично поступает из объявлений, которые явным образом создает программист, а частично — из других языковгях структур. Нсобходимая для реализации статического контроля типов информация должна включать в себя следующее. 1. Для каждой операции должны бгять указаны количество, порядок и тип данных для арзу ивнтов и результатов (иначе говоря, сигпатура операции).
2. Для каждой переменной, представляющей собой имя обьекта данных, следует указать пгип этого обьекта. Тип объекта данных не должен изменяться в пропсссс выполнения программы (оп должен быть и н вариантом). Однако при проверке типов для выражения А + В можно предположить, что тип данных для объекта под именеги А остается неизменным при каждом вычислении выражения, даже если оно вычисляется в цикле и на каждом его шаге переменная А связывается с некоторым новым объектом данных, 3.
Должны быть указаны типгя всех констант. Синтаксическая форма записи литерала ооычно дает информацию о сго тиос (например, 2 — зто целое число, а 2 3 — вещественное). Для проверки типа именованной константы следует использовать ее определение. На начальном этапе трансляции программ компилятор (или другой транслятор) собярает информацию о типах объектов данных из объявлений, имеюгцихся в программе, и вносит сс в различные таблицы, главным образом в таблицу символов (см. главу 3), которая содержит сведения о типах псрсмсццых и операций.
После того как собрана вся вта информация, происходит проверка всех вычисляемых в программе операций па правильность типов их аргументов. Заметим, что, как отмечалось ранее, для полиморфоых операций любой пз нескольких возможных типов аргументов будет воспринят как правильный. Если все аргументы для данной операции прошли провсрку, то определяется тип результата и полученная информация сохраняется компилятором для проверки последующих операций. Обраюгте внимание на то, что в случае полиморфной операции опять-таки общее (групповое) имя может быть заменено имецсм, специфическим для конкретного типа данных передаваемых сй аргументов. Поскольку статический контроль типов осуществляется для всех бсз исключения операций, имеющихся в программе, то проверяются все возможные ветви программы и в дальнейшем контроле пс возникает необходимости. Таким образом, не требуется включать в объекты данных дескрипторы типов и производить динамическийий' контроль типов.
В результате получается значительный выигрьпп в скорости выполнения программы и эффективности использования памяти. Стремление реализовать статический контроль юшов оказывает значительное влияние ца многие аспекты языка: объявления, структуры управления данными, 198 Глава 5. Элементарные типы данных организацию раздельной компиляции подпрограмм и т, д, Во многих языках не всегда можно осуществить статический контроль типов для некоторых конструкций в определенных случаях. Подобные проблемгя со статическим контролем типов в некоторых языковых с груктурах можно решать двумя способами.
1. Отказатьсн от стати чвскосо контроля в пол»зу динамического. Цена такого решения часто оказывается высокой в отношении используемой памяти, так как во время выполнения программы требуется хранить дескрипторы типов для всех обьектов данных, хотя онн и редко проверяются. 2. Вооби1в отказаться от контроля типов для операций. Не проверенные на соответствие типов аргументы операции могут вызвать серьезные н трудноуловимые опшбки в программах, но иногда приходится исполыовать этот вариант, если стоимость динамического контроля типов оказывается слишкомм высокой. Сильная типизация. Если мы можем при помощи статического контроля обнаружить все без исключения ошибки определения типов в программе па данном языке, то такой язык называется силыю типизированным.
Вообще говоря, строгий контроль типов является некоторой гарантией отсутствия соответствующих ошибоквпрограмме. Мы называемфункцию1сспгнатурой1 . 5 — » Кбезопаснойвотношении типа, если при вычислении этой функции результат не может выйтн за пределы множества к, В случае всех операций, безопасных в отношении типа, мы знаем егце до выполнения программы, что тип результата будет правильным и что динамический контроль типов не требуется. Очевидно, если каждая операция безопасна в отношении типа, то язык в целом является сильно типизированным.
Однако немногие языки соответствуют этому требованию. Например, в языке С, если х н У принадлежат типу зйог1 (то есть короткие целые числа), то результат операций Х + У или Х " У может оказаться за пределами этого типа, вследствие чего возникнет ошибка типа. Хотя реализация в языке настоящего строгого контроля типов трудна, можно значительно приблизитъся к ней, если ограничить преобразование одного типа в другой, о котором пойдет речь в следуюгцем разделе. Выведение типа. В языке МЕ предложен интересный подход к определению типов данных. Суть его в том, что в случае, если возможна однозначная интерпретация типа данных, его объявление не требуется. Язык реализован таким образом, что недостающая информация о типах данных может быть выведена пз других имеющихся объявлений типов.
В этом языке для объявления аргументов функций используется достаточно стандартный синтаксис, а именно гвл агеанелдгщ~л:. »посл.~ос) ~пс = 1епдсь *»лссщ В данном случае функция агеа возвращает целое число — величину площади прямоугольника, которая вычисляется как результат перемножения двух целочисленных аргументов, длины и ширины. В данном случае, если определен тип хотя бы одного из этих трех объектов данных: агеа, 1елдгй или»лг1гй, то можно вывести типы двух других.
То есть, даже исключив описание типов каких-то двух параметров, мы все же получаем однозначную интерпретацию этой функции. Поскольку символ «*» может означать и целочисленное, и вещественное перемножение, каждая из приведенных далее форм записи в М1. эквивалентна записи из предыдуп1его примера: 5.1. Свойства типов и объектов 199 гоп агеа(1еорсш иштп1.1от = 1еореь " и10Ф: гоо агеа(1еодсш1осх ювгь1 = 1епягь * ишш: Гоо агеа11еодсо. ищтщ1о 1 " 1еор Ь * ии1Ф: Однако такая запись Гоо агеш1епрей, ищсй = 1еояер * и1ВГЬ: уже ошибочна, так как в ней отсутствует однозначность определения типов данных.
В такой записи все используемые объекты данных могут быть либо целыми, либо вещественными. Приведение и преобразованиетипов сслн в процессе проверки типов выявляется несоответствие между фактическим и ожидаемым типалщ аргумента для операции, то может произойтн одно из двух: 1) ПЕСоотрстетвис типов будет восп1аинято как ошибка, о чем появится сообщенпе, и будут предприняты предуеиетре11ные для такого случая действия; 2) произойдет приведеяпе (или неявное, преобразование) типа' фактически переданного аргумента к правильному, ожидаемому для данной операции: сооиегюоо ор; гуре1 -а гурег Иначе говоря, преобразование типа заключается в том, что вместо объекта данных одного типа создастся соответствующий ему новый объект друпно типа.
В большинстве языков преобразование типов осуществляется одним из следующих двух способов. 1. Набором встроенных функций, которые программист может вызвать явнтям образом для преобразования типа какого-либо объекта. Например, в языке Рааса! имеется функция гоппд, которая преобразует объект данных вещественного типа в целочисленный объект, значение которого равно округленному значению вещественного числа. В языке С мы принудительно приводим (саят) выражение к правильному типу. Например, операция Н п11 Х преобразует вещественное х в объект целого типа.
2. Приведением типа, которое осуществляется автоматн ~ески в определенных случаях несоответствия типа. Например, в языке Рааса!, если арифметической операции сложения переданы аргументы различных типов — вещественного и целочисленного, то по умолчанию целочисленный тип преобразуется в вещественный и затем осуществляется вещественное сложение.
В отличие от С++ в 1 ага неявное приведение тинов допускается, если сама операция допускает расширение. Таким образом, в ~ага целочисленное значение может быть присвоено перемешюй вещественного типа, а в С++ следует преобразовать тип значения в вещественный явным образом, В основе неявного приведения типов лежит концепция недопущения потери информации. Имеется в виду следующее: поскольку в языке С любое короткое аслочнсленное значение может быть преобразовано в длинное, при автоматическом преобразовании зйогг 1пт — > 1опя 1пт не происходит потери информации. Такое приведение называется расширением. Аналогично, поскольку в большин- 11усобушоивяие тняа — это оосраиия с сигиатурой.