Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Ещё одна методичка по ЛО.doc
Скачиваний:
18
Добавлен:
23.03.2016
Размер:
433.15 Кб
Скачать

2.1.3. Виды и уровни типизации

Приведем теперь классификацию языков программирования по способу определения семантики языковых конструкций.

Если семантика каждой языковой конструкции (например, операций) определяется по тексту программы, а не во время ее выполнения, т.е. статически, язык называется статически типизированным, в противном случае -- динамически типизированным. Не надо путать статическую и динамическую типизацию со статическим и динамическим контролем типов:

статически типизированные языки чаще всем являются языками со смешанным контролем типов (ПЛ/1, Паскаль, Ада).

Однако чем меньше язык использует динамическую типизацию (т.е. чем он более статически типизирован), тем больше возможностей для статического контроля типов и вообще для повышения эффективности языка. Поэтому большинство языков программирования статически типизированы.

Статически типизированные языки классифицируются по трем уровням типизации, отвечающим различным требованиям к их надежности:

слабо типизированный, если информация о типе используется только для обеспечения корректности программы на машинном уровне;

сильно типизированный, если осуществляется полный контроль типов (статический, динамический или смешанный);

защитно типизированный, если программы, содержащие конструкции с возможными типовыми ошибками, считаются недопустимыми, даже если эти ошибки никогда не могут возникнуть (в этом отличие от сильно типизированных языков).

Рассмотрим проблемы, возникающие для языков того или иного уровня типизации.

В слабо типизированных языках (ПЛ/1, Алгол-68, Си т.д.) операция, которая может восприниматься машиной как корректная, может быть некорректной на абстрактном уровне программы. Например, символьная переменная

С: character;

используется в следующем операторе присваивания:

С:=4;

Слабо типизированный язык вполне может допустить этот оператор: на машинном уровне символы представлены целыми числами в диапазоне от О до 255. Следовательно, для ЭВМ это корректно. Однако на абстрактном уровне программы это не так.

Возможно, именно это программист имел в виду, но гораздо более вероятно, что он допустил ошибку, намереваясь написать

С:=' 4';

При работе с разными типами для сохранения корректности в слабо типизированных языках предусмотрено выполнение операций преобразования типа. Например, если встретится описание

X, Y: real;

I, J, K: integer;

то присваивание

I:=X;

потребует преобразования вещественного объекта Х перед его присваиванием объекту I из его внутреннего представления с плавающей точкой в целое представление. Разумеется, эта операция приведет к ошибке, если значение Х выходит из реализуемой области целых чисел, но предупреждения об этом в программе нет. Еще одна проблема, связанная с неявным преобразованием типа, состоит в необходимости совершенного знания языка для точном определения порядка и правил преобразований типов, выполняемых в произвольно составленных выражениях. Например, непонятно, какую операцию преобразования нужно выполнять сначала в операторе присваивания

К:=Х-J;

Нужно ли сразу Х преобразовывать в целый тип или сначала J в вещественный тип, а затем Х-У обратно в целый? Заметим, что если Х превышает максимальное целое значение, то первое приведет к ошибке, а во втором случае этого может и не произойти. Другой пример связан с тем, что в силу правил неявных преобразований некорректная программа может иметь законную, но не очевидную интерпретацию, и поэтому ее трудно отлаживать. Например, в ПЛ/1 каждое из выражений 1<2<3 и 3<2<1 законно и дает результат "истина" из-за преобразований между целыми и логическими значениями. Еще один недостаток неявных преобразований состоит в том, что программист может не знать о связанных с преобразованиями больших затратах времени и памяти при выполнении программы. И, наконец, наличие неявных преобразований усложняет язык, снижает эффективность компилятора.

В слабо типизированных языках для некоторых типов часто разрешается выполнение некорректных операций. Например, наряду с нормальными арифметическими операциями можно для целых типов определить операции логическом сложения и операции сдвига. Хотя это и повышает гибкость языка, но снижает понятность и надежность программ.

В сильно типизированных языках (например, Ада) для следующих описаний:

Х: real;

I: integer;

В: boolean;

С: character;

все перечисленные ниже операторы присваивания ошибочны:

а) I:= 'А'; -- различные типы левой и правой части

b) Х:= I; -- то же

с) С:= 10; -- то же

d) I:= I or 7; -- операция or принадлежит логическому типу

Ясно, что некоторые присваивания вида b) необходимы. Для этого должны использоваться функции явного преобразования типа, например

Х:=real(I);

где функция с именем, совпадающим с именем типа real, применяется к целому значению I и дает вещественный результат.

Сильная типизация резко повышает надежность и ясность программ. Всем операциям языка на абстрактном уровне обеспечивается корректность.

Незаконным считается присваивание значения одного типа данных объекту данных другого типа, даже если внутреннее представление обоих типов идентично. В каждом из таких случаев присваивания должна явно применяться функция преобразования типа. Даже тогда, когда результат ее выполнения эквивалентен тождественному преобразованию, как, например, в операторе

С:=character(10);

включение функции преобразования необходимо, так как заставляет программиста недвусмысленно заявить, что он намеренно выполняет необычную операцию и что это не ошибка.

Защитная типизация еще более повышает надежность языка, не допуская даже потенциальных типовых ошибок. Однако она отрицательно сказывается на мощности языка. Довольно близко к защитной типизации подошел язык Паскаль.