Т. Пратт, М. Зелковиц - Языки программирования - разработка и реализация (4-е издание_ 2002) (1160801), страница 81
Текст из файла (страница 81)
Но чаще все-таки конструкция 1урейег применяется для создания новых типов, и в большинстве языков оиа используется как объявление нового тина данных. Помимо упрощения структуры подпрограммы определение типов имеет и другие ттреимущсс> ва лля программиста. Если цо какой-либо причине нужно будет модифицировать определение типа ка1>опа1, то это можно б>уисет слелать в одном только месте и не ирилется с>тыскивать и перелелывать определения лля каждого экземпляра переменных этого типа. Также в случае, если иеремснная нового типа передастся в качестве парал>етра какой-либо подпрограмме, обычно в ией должно присутствовать описание этого нового типа.
Если у нас имеется определение типа, то мы просто указываем, что данная переменная принадлежит этому типу, вместо того чтобы повторять все ооисацие структуры этих объектов заново. 6.4. Определения типов 287 Определение типа используется как щиблон для конструирования объектов данных во время выполнения программы. Объект данных нового типа может быть созлан или на вхоле в подпрограмму (если объявление переменной этого типа присутствует среди обьявлений других локальных данных в этой подпрограмме), или динамически во время выполнения подпрограмлп ~ при помощи некоторой специальной операции создания (наприлгер, ва11ос, которая обсуждалась в разделе 5.3.2). Во втором случае доступ к созданному объекту осуществляется при помощи указателей.
Использование определения типа в качестве шаблона аналогично использованию определения подпрограммы, описанному в предыдущем разделе. Определение типа позволяет отделить определение структуры объекта данных от определения тех точек во время выполнения программы, в которых эти объекты создавтсл. Заметим также, что у нас появляются новые способы идхилсуляции и сокрьилия информации. Переменную в подпрограмме можно опрелелить как относящуюся к некоторому типу, просто указав имя этого типа.
Определение типа фактически скрывает внутреннюю структуру объекта данных этого типа. Если подпрограмма просто создает объекты данных некоторого типа, используя его имя, но никогда ие осуществляет доступ к внутренним компонентам этого объекта данпых, то подпрограмма становится фактически независимой от конкретной структуры, объявленной в опрелелении типа. То есть зто определение можно модифицировать, нс меняя при этом подпрограмму. Если идеология языка позволяет ввести ограничения на то, что лишь некоторые специальным образом указанные подпрограммы смогут иметь доступ к внутренним компонентам объектов ланных, а все остальные подпрограммы эти объекты будут воспринимать как единое целое, то определение типа фактически инкапсулирует структуру объектов данных этого типа.
В следующем разлеле мы рассмотрим, как полобная инкапсуляция позволяет программисту сконструировать полный абстрактный тип данных. Реализация. Информация, содержащаяся в объявлении переменной, в первую очередь используетгя во время трансляции лля определения способа прелставления в памяти соответствующего объекта данных, управления ресурсами памяти и контроля типов. Во время выполнения программы обьявления отсутствуют; они нужны только для того, чтобы правильным образом создать во время выполнения необходимые объекты данных. Аналогично и оп релел ение типа используется только во время трансляции.
Транслятор языка заносит информацию, полученную из определения типа, в специальную таблицу и, когда имя типа встречается в последующих обьявлениях, использует данные из этой таблицы для того, чтобы созлать соответствующий втогау типу исполняемый код для создания объектов данных этого типа и манипулирования ими. Определение типа позволяет осуществлять некоторые аспекты трансляции, такие как определение способов представления ооъектов в памяти, только один раз, а не повторять многократно при каждом упоминании этого типа в объявлениях.
Тем не менее наличие в языке средств лля определения типов, как правило, не влияет на способ реализации языка. 6.4.1. Эквивалентность типов Проверка типов, с гатичсская или динамическая, вкл1очаст в себя сравнение типа данных фактического аргумен.щ, переданного операции и ожидаемого для этой 288 Глава б. Инкапсуляция операции типа данных. Если эти типы одинаковы, то аргумент принимается и операция выполняется. Если эти типы различны, то либо создавшаяся ситуация расценивается как ошибка, либо применяется приведение типа аргумента к ожидаемому. Понятие эквивалентности тинов поднимает вопрос о двух связанных понятиях.
1. Что означает высказывание «два типа одинаковы»? 2. Что означает высказывание «объекты данных одного и того же типа равны между собой»? Первое понятие из области проблем типов данных. Если мы можем определить тип данных статически, то мы имеем дело со строго типизированным языком. Второе понятие относится к области семантики и связано с определением г-значения объекта данных. Равенство типов. Ког11а тип Х равен типу Х? Мы по большей части старались игнорировать этот тонкий вопрос при обсуждении элементарных типов данных, таких как целые числа илп массивы (хотя этот вопрос затрагивался, когда речь шла о подтипах элементарных типов).
Определения типов требуют ясного ответа на этот вопрос, если мы хотим, чтобы язык был четко и ясно определен. Рассмотрим определения тинов и объявления в программе, приведенной в листинге 6.3. Наш вопрос заключается в следующем: одинаковы ли типы данных переменных Х, У, 2 и А. В случае положительного ответа па этот вопрос операция присваивания Х:= У и вызов подпрограммы 50011 с параметром Х будут иметь вполне законное основание, в противном слу ~ае оба этн действия становятся недействительными.
Листинг б.б. Равенство типов ргодгав ваапыпроц оо1рог): туре уес11: аггау О..103 оу геа1; уес12: аггау(1. 10)оу геа1; маг Х д . Хес11. у уес12 ргосевоге 5«ЫА; Чес11 Е епш Ьедап Х =У: 5ощу1 — славная программа «аг я, аггау 11...101 оу геа1 епв Суп 1естаует два способа решегпи этой проблемы: эквивалентность имен и структуриая эквивалентность, Эквивалентность имея. Два типа данных считаются эквивалентными, если они имеют одинаковое имя. Таким образом, Уес11 и Уес02 считаются различными типами, даже если объекты данных этих типов игасют одинаковую структуру. Тогда правильной будет операция присваивания Х .= 2, но пе операция Х:= У. Метод эквивалентности имен используется в языках Ада, Се« и для параметров подпрограмм в Рааса! (лля остальных случаев в Раэса1он не применяется). Эквивалентность имен как способ определения эквивалентности типов илхеет следующие недостатки.
1. Тип каждого объекта, используемого в операции присваивания, должен иметь определенное имя. Алонкин ые типы не допускаются. Декларация языка Рааса! 6,4, Определения типов 289 вполне однозначно определяет тип массива ч1, но переменная й не может быть передана подпрограмме в качестве фактического параметра, поскольку ее тип не имеет имени. 2. Единственное определение типа лолжно использонаться во всей программе или н большей ее части, поскольку тин объекта данных, переданного н качестве фактического параметра по цепочке полпрограмм, не может заново определяться в каждой пояпрограгилае — должно использоваться единое глобальное опрелсление тина.
Средствами лля этого являются определения классон в С+ +, файлы включения н С и имена пакетов спецификаций в Аг1а. Структурная эквивалентность. Дна типа данных считаются эквивалентными, если соответствующие им объекты лап ных пмсютнрди на ковую внутреннюю струк- туру, то есть состоят из олинаковых компонентов. Обычно зто означает, что лля обоих классов объектов можно использовать один и тот же способ их прелставле- ния в памяти.
Например, Нес11 и Нес12 при таком ш>лхолс булут считаться акнива- лентными типами, поскольку каждый объект ланных типа нес11 и каждый объект данных типа Нес12 игиеют н точности одинаковое число компонентов эквивалент- ных типов, расположенных в олпом и том же порядке, Представление объектов данных каждого типа в памяти одинаково, поэтому для выборки их компонентов можно использонать одну и ту же формулу доступа; вообще, реализации атих ти- пов данных во время выполнения полностью идентичны. Структурная эквивалентность типов лишена недостатков, характерных лля равен- ства типов па основе эквивалентности имен, но имеет целый ряд своих недостатков. 1.
При попытке применить принцип структурной эквивалентности типов возникают некоторые проблемы. Напримср, в ела ае записей должны ли совпадать имена компонентов или достато шо только совпадения их тинов, количества и порядка следования? Если же имена компонентов записей должны совпадать, требуется ли тогла сонпалснис их порядка? Должны ли сон цапать диапазоны значений индексов Лля массивов или Лостаточ 0 о только совпадения числа компонентов? Должны ли совпадать литералы и порядок их следования лля двух перечислений? 2. Две перемен пыс случайно могут оказаться структурно эквивалентными, хотя программист определял их как принаялежап1ие к различным типам данных, в чем можно убедиться на следующем простом примере: тчне МеГега = 1пгенег; О Гага = ~пЩег, чаг Геп Ие1ега, НШ Шгегы Переменные Нес11 и Нес12 имеют структурно эквивалентные типы, и поэтому такая ошибка, как, например, вычисление суммы Нес11 + Нес12 не будет обнаружена при статической проверке тинов.
Когла несколько программистов пишут олпу большу1о программу, непрелпамеренпое совпадение типов различных объектов может привести к тому, что будут утрачены все преимущестна статической проверки типов, так как многие ошибки определения типов могут остаться незамеченными. 3. Частая проверка эквивалентности типов в случае сложных определений их структур может значительно увеличить стоимость трансляции. 290 Глава б.
Инкапсуляция Вопросы, связанные с выбором способа определения эквивалентности типов, играют важную роль в идеологии таких языков, как Айа и Рааса), где эквивалентность типов имеет большое значение, В более старых языках, таких как РО[[ТКАЬ[, СОВО[. и Р[./1, где определения пользовательских типов отсутствуют, используется некое подобие структурной эквивалентности. В языке Рааса) вопрос эквивалентности типов ставится, но он не решается последовательно с использованием только одного из рассмотренных способов. В языке С используется структурная эквивалентность типов. В языке С++, как было сказано ранее, используется эквивалентность имен (в этом — одно из тонких различий между языками С и С++).
В языке Айа в настоящее время используется эквивалентность имен, но пока этот вопрос еще находится в стадии исследований (см. задачи и ссылки на рекомендуемую литературу в конце этой главы). Равенство объектов данных. Когда компилятор определил, что два объекта данных имеют олин и тот же тип, можно поставить вопрос о равенстве этих объектов. Предположим, что переменные А и В имеют один и тот же тип Х.