Выделив на шаге 3.1 операционную абстракцию – функцию все_связи, мы немедленно ощутили потребность обозначить классы возможных аргументов и результатов этой функции, не занимаясь их детальной проработкой. Если бы приходилось работать на Фортране, Алголе-60 или Бейсике, сделать это оказалось бы невозможным - непосредственно подходящих предопределенных типов данных в этих ЯП нет, а возможность строить новые типы также отсутствует. Скорее всего пришлось бы нарушить естественный порядок детализации и сначала придумать способ представлять "связи" некоторым массивом, а затем учесть, что в этих ЯП функции не вырабатывают результаты-массивы (только скаляры), и представить нужную абстракцию не функцией, а процедурой. Важно понимать, что такого рода отклонения запутывают логику программы, провоцируют ошибки, затрудняют отладку и т. п.
Лучшее, что можно сделать в этом случае, - выйти за рамки используемого ЯП и фиксировать шаги детализации на частично формализованном псевдокоде. О применении такого псевдокода в структурном подходе к программированию на классических ЯП можно прочитать, например, в [6].
В Аде мы смогли провести шаг детализации полностью в рамках языка. Причем, вводя операционную абстракцию, были вынуждены воспользоваться средствами определения абстракций другого рода - абстракций данных. Точнее говоря, на шаге 3.1 мы воспользовались лишь тем, что в Аде можно вводить новые абстракции данных и можно вводить для этих абстракций подходящие названия.
Обратите внимание, мы ввели не названия отдельных объектов данных (только так и можно в классических ЯП), а именно названия целых классов (типов) обрабатываемых объектов.
Определения типов мы также имели возможность вводить по шагам, вполне аналогично тому, как в классических ЯП вводят операционные абстракции, выделяя нужные процедуры. На шаге 3.1 обозначили новый тип "связи"; на шаге 3.5 уточнили его строение, но потребовались названия типов число_связей и перечень_связей. На шагах 3.6 и 3.7 уточнили строение этих типов, но остались неопределенными макс_узлов и макс_связей. Наконец, уточнили их характеристики и даже значения.
Четкость пошаговой детализации поддерживалась языковыми средствами связывания. Можно было не заботиться о реализации процедур и функций - ее можно определить позже, в теле пакета - средства связывания обеспечат согласованное использование спецификаций и тел процедур. В классических ЯП так поступить нельзя, пришлось бы опять выходить за рамки языка или нарушать порядок детализации и выписывать тела процедур (а это не всегда можно сделать, еще не зная структуру используемых данных).
Итак, должно быть видно, как принцип согласования основных абстракций (между собой и с потребностями пошаговой детализации) воплощен в Аде. Во-первых, согласованность основных абстракций действительно требовалась и, во-вторых, Ада необходимые выразительные средства предоставляет.
Принцип цельности дает основания ввести критерий технической оценки языка, который можно назвать критерием цельности: язык тем лучше, чем ближе он к идеалу с точки зрения принципа согласования абстракций. Ясно, что с точки зрения технологии пошаговой детализации Ада превосходит классические ЯП по этому критерию.
Упражнение. Пользуясь критерием цельности, оцените другие известные ЯП.
4. Данные и типы
4.1. Классификация данных
Рассматривая три выделенные роли в акте исполнителя, мы подчеркивали, что с ролью данных ассоциируется пассивное начало. Это не означает и не требует полной пассивности объекта, выступающего в роли данного, а лишь его относительной пассивности с точки зрения рассматриваемого акта поведения того исполнителя, планирование поведения которого нас интересует. Тот же объект с другой точки зрения может быть активным и даже сам выступать в роли исполнителя. В качестве примера можно привести задачу управления асинхронными процессами, когда осуществляющий управление исполнитель вправе рассматривать эти (активные) процессы как данные, на которые направлено его управляющее воздействие.
Данными обычно считают любые обрабатываемые объекты независимо от их внутренней природы. Одна и та же категория объектов в одном ЯП может выступать в роли данных, а в другом это может быть запрещено. Так, процедуры могут быть данными в Паскале и Алголе-68 (их можно передавать в качестве значений, присваивать компонентам других объектов), но не в Аде.
Данные различаются по многим признакам.
Во-первых, данные можно классифицировать по содержательным ролям, которые они играют в решаемой задаче. Очень заманчиво было бы уметь явно отражать в программе результаты такой классификации с тем, чтобы сделать ее доступной как исполнителю, так и читателю программы. По существу это прогнозирование поведения определенных объектов данных (например, прогноз о том, что переменные А и В никогда не могут быть операндами одного и того же сложения). Прогноз такого рода облегчает понимание программы и создает предпосылки для автоматического содержательного контроля.
Возможность отражать содержательную классификацию данных отсутствует в большинстве классических ЯП. В Аде сделаны шаги в нужном направлении. Например, мы различали типы "узел", индекс_узла и число_связей, хотя все они в конечном итоге представлены целыми числами.
Во-вторых, данные различаются по своему внутреннему строению, структуре, характеру связей своих составляющих. Например, массивы, таблицы, списки, очереди. С этой точки зрения важен способ доступа к составляющим данных. Классификация данных по способу доступа к составляющим обычно имеется в виду, когда говорят о структурах данных. Классификация данных по их структуре есть в том или ином варианте почти во всех ЯП. В современных ЯП чаще всего выделяются массивы и записи. И то, и другое можно считать частным случаем таблиц, которые служат ключевой структурой, например, в МАСОНе [10] и его последующих модификациях.
В-третьих, данные различаются по своей изменчивости. Например, в некоторых случаях известен диапазон возможных изменений или известно, что данное вообще не должно меняться. Прогнозирование поведения такого рода встречается только в относительно новых ЯП, начиная с Паскаля.
В-четвертых, данные могут различаться по способу своего определения. Их свойства могут быть предопределены (т. е. определены автором ЯП) или же определены программистом с помощью языковых средств. В последнем случае в идеале это такие средства, которые позволяют программисту по существу определить новый язык, обогащая исходный.
Как правило, предопределенные объекты и свойства не могут быть изменены программистом и в этом смысле надежно защищены от искажений. У программиста должна быть возможность принять меры к тому, чтобы вновь введенные им абстракции были неотличимы от предопределенных. Это еще одна формулировка принципа защиты абстракций.
Если защита обеспечена, то на каждом шаге обогащения ЯП появляется полная
возможность действовать так, как будто в распоряжении программиста появился виртуальный исполнитель для сконструированного уровня абстракции. Подчеркнем, что при этом детализация осуществляется от задачи к реализации (сверху вниз), а создание виртуальных машин - в общем случае от реальной машины к задаче (снизу вверх). Аппарат для определения данных, ориентированный на принцип защиты абстракций, имеется только в новейших ЯП, в частности, в Аде, Модуле-2, последних версиях Паскаля и др.
В-пятых, данные могут различаться по своему представлению на более низком уровне абстракции (на реализующей виртуальной машине, в терминах реализующей структуры данных, по классу необходимых для реализации ресурсов, по объему и дисциплине использования памяти и т. п.). Например, для чисел может требоваться одно, два или несколько слов в зависимости от нужной точности вычислений, память для данных одной категории может выделяться в некотором стеке (например, для локальных данных блоков) или в так называемой куче (для элементов динамически изменяемых списковых структур), для некоторых данных разумно выделять самую быструю память (например, быстрые регистры для переменной цикла). Это еще одна форма прогнозирования поведения объектов - запрос для них подходящих ресурсов. Классификация с точки зрения представления встречается практически во всех ЯП, ориентированных на эффективное использование ресурсов машины, в частности, в языке Си.
В-шестых, данные могут различаться по применимым операциям (внешним свойствам), определяющим возможности данного играть определенные роли или вступать в определенные отношения с другими объектами программы.
Например, если данное представляет собой число, символ, указатель, задачу, очередь, стек, то в каждом из этих случаев к нему применим определенный набор операций, у него имеется определенный набор атрибутов, характерных для данных именно этого класса, и т. п. Чтобы не было путаницы с первым фактором классификации (по содержательным ролям), подчеркнем, что переменная для хранения числа апельсинов может отличаться от переменной для хранения числа яблок по содержательной роли, но не отличаться по применимым операциям. А вот объекты типов "узел" и индекс_узла различаются по применимым операциям (по каким?).
Наконец, в-седьмых, данные могут различаться по характеру доступа к ним. Одни данные считаются общедоступными, другие могут использоваться только определенными модулями или при определенных условиях и т. п.
В заключение подчеркнем, что указанные факторы ортогональны. Классификация не претендует на полноту, но позволит ориентироваться, в частности, в системе управления данными в Аде. Дополнительные факторы классификации предложены, например, в языке Том [7].
4.2. Типы данных
Классификация данных присутствует в каждом ЯП. В Алголе-60 она отражена в системе классов и типов (классы - процедуры, метки, простые переменные, массивы, переключатели; типы - целый, вещественный, логический), в Фортране - также в системе классов и типов (классы имен - массив, переменная, внутренняя функция,
встроенная функция, внешняя функция, подпрограмма, переменная и общий блок; типы - целый, вещественный, двойной точности, комплексный, логический, текстовый). В более современных ЯП имеется тенденция полнее отражать классификацию данных в системе типов, а само понятие типа данных меняется от языка к языку.
|
Из за большого объема этот материал размещен на нескольких страницах:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |


