учебники, программирование, основы, введение в,

 

От Simula к Java и далее: основные ОО-языки и окружения

Simula
Simula - это несомненный основатель Дома Классов (Дворца Объектов). Создание его было завершено (если не принимать во внимание небольшие более поздние обновления) в 1967 г. В это, возможно, трудно поверить: оформившийся ОО-язык существовал и был реализован до структурного программирования, до публикации Парнасом статей по скрытию информации, задолго до появления фразы "абстрактный тип данных". Война во Вьетнаме еще освещалась в газетах, мини-юбки еще могли возбуждать, а на северных берегах Балтики несколько удачливых разработчиков ПО, ведомые горсткой мечтателей, уже использовали силу классов, наследования, полиморфизма, динамического связывания и других прелестей ОО.
Основные понятия
Simula, по существу, является второй попыткой. В начале 60-х был разработан язык, известный как Simula 1, для поддержки моделирования дискретных событий. Хотя он не был ОО-языком в полном смысле термина, но суть он уловил. Собственно Simula - это Simula 67, созданный в 1967 г. Далом и Нигардом (Kristen Nygaard, Ole-Johan Dahl) из Университета Осло и Норвежского Компьютерного Центра (Norsk Regnesentral). Нигард потом объяснял, что решение сохранить название отражало связь с предыдущим языком и с сообществом его пользователей. К несчастью, это название долгое время для многих людей создавало образ языка, предназначенного только для моделирования событий, что было довольно узкой областью приложения, в то время как Simula 67 - это общецелевой язык программирования. Единственные его компоненты моделирования - это набор инструкций и библиотечный класс SIMULATION, используемый небольшим числом разработчиков Simula.
Название было сокращено до Simula в 1986 г., текущий стандарт датируется 1987 г.
Доступность
Simula часто представляется как респектабельный, но более не существующий предок. В действительности он еще жив и используется небольшим, но восторженным сообществом. Определение языка поддерживается Группой Стандартов Simula (Simula Standards Group). Существуют компиляторы и ПО от нескольких компаний, в основном скандинавских.
Основные черты языка
Рассмотрим в общих чертах основные свойства Simula. Автор не обидится, если читатель перейдет к следующему разделу о Smalltalk. Но чтобы полностью оценить объектную технологию, стоит потратить время на изучение Simula. Концепции представлены в их первоначальной форме, и некоторые возможности еще и теперь, спустя тридцать лет, не полностью использованы.
Simula - ОО-расширение языка Algol 60. Большинство правильных программ на Algol также являются правильными на Simula. В частности, основные структуры управления такие же, как в Algol: цикл, условный оператор, переключатель (низкоуровневый предшественник команды case в Pascal). Основные типы данных (целые, действительные и т. д.) тоже взяты из Algol.
Как и Algol, Simula использует на самом высоком уровне традиционную структуру ПО, основанную на понятии главной программы. Выполняемая программа - это главная программа, содержащая ряд программных единиц (подпрограмм или классов). Программная среда Simula поддерживает независимую компиляцию классов.
Simula использует структуру блока в стиле Algol 60: программные единицы, такие как классы, могут быть вложены друг в друга.
Все реализации Simula поддерживают автоматическую сборку мусора. Есть маленькая стандартная библиотека, включающая, в частности, двусвязные списки, используемые классом SIMULATION, изучаемым далее в этой лекции.
Как и в нотации этой книги, большинство общих сущностей, не относящихся к встроенным типам, обозначают ссылки на экземпляры класса, а не сами экземпляры. Однако это их явное свойство, подчеркиваемое нотацией. Тип такой сущности объявляется как ссылочный ref(C), а не просто C, для некоторого класса C. Для них используются специальные символы для присваивания, проверки на равенство и неравенство (:-, ==, =/= ), в то время как целочисленные и действительные операнды используют другие символы для этих целей (:=, =, /=). Выше в одной из лекций даны обоснования за и против этого соглашения.
Для создания экземпляра используется выражение new, а не команда создания:
ref (C) a; ...;a :- new C
Выражение new создает экземпляр C и возвращает ссылку на него. Класс может иметь аргументы (играющие роль аргументов процедур создания в нашей нотации):
class C (x, y); integer x, y
begin ... end;
В этом случае при вызове new следует передать соответствующие фактические аргументы:
a :- new C (3, 98)
Аргументы могут использоваться в подпрограммах класса. Но в отличие от возможности использования нескольких команд создания (конструкторов), данный подход дает только один механизм инициализации.
Кроме подпрограмм и атрибутов, класс может содержать последовательность инструкций, тело класса. Если тело существует, то вызов new будет выполнять его. Мы увидим, как использовать эту возможность, чтобы заставить классы представлять не пассивные объекты, как в большинстве других ОО-языков, а активные элементы, подобные процессам.
Механизм утверждений в языке не поддерживается. Simula поддерживает единичное наследование. Вот как класс B объявляется наследником класса A:
A class B;
begin ... end
Для переопределения компонента класса в классе наследника, нужно просто задать новое объявление. Оно имеет приоритет над существующим определением (эквивалента оператора redefine нет).
Первоначальная версия Simula 67 не имела явных конструкций скрытия информации. В последующих версиях, компонент, объявленный как protected, недоступен клиентам. Защищенный компонент, объявляемый как hidden, недоступен потомкам. Незащищенный компонент может быть защищен потомком, но защищенный компонент не может экспортироваться потомками.
Отложенные компоненты задаются в форме "виртуальных подпрограмм", появляющихся в параграфе virtual в начале класса. Нет необходимости объявлять аргументы виртуальной подпрограммы, как следствие, разные эффективные определения виртуальной подпрограммы могут иметь разное число и типы аргументов. Например, класс POLYGON может начинаться так:
class POLYGON;
virtual: procedure set_vertices
begin
...
end
позволяя потомкам задавать различное число аргументов типа POINT для set_vertices: три - для TRIANGLE, четыре - для QUADRANGLE и т. д. Эта гибкость подразумевает некоторую проверку типов во время выполнения.


Пользователям C++ следует опасаться возможной путаницы: хотя С++ был инспирирован Simula, он использует другую семантику virtual. Функция С++ объявляется виртуальной, если целью является динамическое связывание (как отмечалось, это один из самых противоречивых аспектов С++, разумнее динамическое связывание подразумевать по умолчанию). Виртуальным процедурам Simula соответствуют "чистые виртуальные функции" C++.

Simula поддерживает полиморфизм: если B - потомок A, присваивание a1 :- b1 корректно для a1 типа A и b1 типа B. Довольно интересно, что попытка присваивания почти рядом: если тип b1 является предком типа a1, присваивание будет работать, если во время выполнения объекты имеют правильное отношение соответствия - источник является потомком цели. Если соответствия нет, то результатом будет ошибка во время выполнения, а не специальная величина, обнаруживаемая и обрабатываемая ПО (как при попытке присваивания). По умолчанию связывание статично, за исключением виртуальных подпрограмм. Поэтому если f - не виртуальный компонент, объявленный в классе A, a1.f будет обозначать A версию f , даже если есть другая версия в B. Можно при вызове насильно задать динамическое связывание через конструкцию qua, как в:
(a1 qua B). f
Конечно, теряется автоматическая адаптация операции к ее целевому объекту. Однако можно получить желаемое поведение динамического связывания (его можно считать изобретением Simula), объявляя полиморфные подпрограммы как виртуальные. Во многих рассмотренных примерах полиморфная подпрограмма не была отложенной, но имела реализацию по умолчанию с самого начала. Для достижения того же эффекта разработчик Simula добавит промежуточный класс, где подпрограмма виртуальна.
В качестве альтернативы использования qua, инструкция inspect дает возможность выполнять различные операции на сущности a1, в зависимости от фактического типа соответствующего объекта, обязательно представляющего собой потомка типа A, объявленного для a1:
inspect a1
when A do ...;
when B do ...;
...
Этим достигается нужный эффект, но лишь при замороженном множестве потомков класса, что вступает в конфликт с принципом Открыт-Закрыт.
Пример
Следующие фрагменты классов показывают общий колорит Simula. Они соответствуют классам системы управления панелями, проектирование которой рассмотрено в.
class STATE;
virtual:
procedure display;
procedure read;
boolean procedure correct;
procedure message;
procedure process;
begin
ref (ANSWER) user_answer; integer choice;
procedure execute; begin
boolean ok;
ok := false;
while not ok do begin
display; read; ok := correct;
if not ok then message (a)
end while;
process;
end execute
end STATE;
class APPLICATION (n, m);
integer n, m;
begin
ref (STATE) array transition (1:n, 0:m-1);
ref (STATE) array associated_state (1:n);
integer initial;
procedure execute; begin
integer st_number;
st_number := initial;
while st_number /= 0 do begin
ref (STATE) st;
st := associated_state (st_number); st.execute;
st_number := transition (st_number, st.choice)
end while
end execute
...
end APPLICATION
Концепции сопрограмм
Наряду с базисными ОО-механизмами язык Simula предлагает интересное понятие - сопрограмма.
Понятие сопрограммы рассматривалось при обсуждении параллелизма. Дадим краткое напоминание. Сопрограммы моделируют параллельные процессы, существующие в операционных системах или системах реального времени. У процесса больше концептуальной свободы, чем у подпрограммы. Например, драйвер принтера полностью ответственен за то, что происходит с принтером, им управляемым. Он не только ответственен за абстрактный объект, но и имеет собственный алгоритм жизненного цикла, часто концептуально бесконечный. Форма процесса принтера может быть приблизительно такой:
from some_initialization loop forever
"Получить файл для печати"; "Напечатать его"
end
В последовательном программировании связь между единицами программы асимметрична: когда один программный блок вызывает другой, то последний выполняется, после чего возвращает управление вызывающему блоку в точке вызова. Процессы равноправны: каждый процесс выполняется сам по себе, прерываясь временами для предоставления информации другому процессу или ожидая ее получения.
Сопрограммы спроектированы подобным же образом, но для выполнения в одном потоке управления. (Последовательная эмуляция параллельного выполнения называется квази-параллелизмом.) Сопрограмма прерывает свое собственное выполнение и предлагает продолжить выполнение (resume) другой сопрограмме в ее последней точке прерывания; прерванная сопрограмма позже может продолжиться сама.
Сопрограммы особенно полезны, когда каждая из нескольких связанных деятельностей имеет собственную логику. Каждая из них может быть задана последовательным процессом, и отношение "хозяин-слуга", характерное для обычных подпрограмм, является неадекватным. Типичным примером является преобразование входных данных в выходные, где на структуру входных и выходных файлов накладываются различные ограничения. Такой случай будет обсуждаться ниже.
Simula представляет сопрограммы как экземпляры классов. Это уместно, поскольку сопрограммы почти всегда нуждаются в длительно хранимых данных, и с ними ассоциируется абстрактный объект. Как отмечалось выше, класс в Simula может иметь тело. В классе, представляющем абстракцию пассивных данных, оно будет служить только для инициализации экземпляров классов (эквивалент нашей процедуры создания). В сопрограмме оно будет описанием процесса. Тело сопрограммы - это обычно цикл вида
while continuation_condition do begin
... Действия ...;
resume other_coroutine;
...Действия ...
end
Для некоторых сопрограмм условием continuation_condition часто является True, что эквивалентно бесконечному процессу (несмотря на то, что хотя бы одна сопрограмма должна завершиться).
Система, основанная на сопрограммах, обычно имеет основную программу, сначала создающую ряд объектов - сопрограмм, а затем продолжает одну из них:
corout1 :- new C1; corout2 :- new C2; ...
resume corouti
Каждое выражение new создает объект и приступает к выполнению его тела. Но квазипараллельная природа сопрограмм (в отличие от истинного параллелизма процессов) поднимает проблему инициализации. Для процессов каждое new порождает новый процесс, запускает его, возвращая тут же управление исходному процессу. Но здесь только одна сопрограмма может быть активной. Если выражение new запустило основной алгоритм сопрограммы, то исходный процесс не получит вновь управление - у него не будет возможности создать C2 после порождения C1.
Simula решает эту проблему посредством инструкции detach. Сопрограмма может выполнить detach, возвращая управление блоку, создавшему его посредством new. Тела сопрограмм почти всегда начинаются с detach (если необходимо, после инструкции инициализации), а дальше обычно следует цикл. После выполнения своего detach сопрограмма приостановится до тех пор, пока главная, или другая, сопрограмма не продолжит ее выполнение.
Пример сопрограммы
Приведем пример некоторой ситуации, где сопрограммы могут оказаться полезными. Вам предлагается напечатать последовательность действительных чисел в качестве ввода, но каждое восьмое число в выводе нужно опустить. Вывод должен представлять собой последовательность строк из шести чисел (кроме последней строки, если для ее заполнения чисел не хватает). Если in обозначает n-й элемент ввода, вывод выглядит так:
i1    i2    i3    i4    i5    i6
i7    i9    i10    i11    i12    i13
i14    i15    i17    и т. д.
Наконец, вывод должен включать только 1000 чисел.
Эта задача характерна для использования сопрограмм. Она включает три процесса, каждый со своей специфической логикой: ввод, где требуется пропускать каждое восьмое число, вывод с ограничением строки до шести чисел, главная программа, где требуется обработать 1000 элементов. Традиционные структуры управления неудобны при сочетании процессов с разными ограничениями. Решение, основанное на сопрограммах, будет проходить гладко.
Введем три сопрограммы: producer (ввод), printer (вывод) и controller. Общая структура такова:
begin
class PRODUCER begin ... См. далее ... end PRODUCER;
class PRINTER begin ... См. далее ... end PRINTER;
class CONTROLLER begin ... См. далее ... end CONTROLLER;
ref (PRODUCER) producer; ref (PRINTER) printer;
ref (CONTROLLER) controller;
producer :- new PRODUCER; printer :- new PRINTER;
controller :- new CONTROLLER;
resume controller
end
Это главная программа, в обычном смысле этого слова. Она создает экземпляр каждого из трех классов - соответствующую сопрограмму и продолжает одну из них - контроллер. Классы приведены далее:
class CONTROLLER; begin
integer i;
detach;
for i := 1 step 1 until 1000 do resume printer
end CONTROLLER;
class PRINTER; begin
integer i;
detach;
while true do
for i := 1 step 1 until 8 do begin
resume producer;
outreal (producer.last_input);
resume controller
end;
next_line
end
end PRINTER;
class PRODUCER; begin
integer i; real last_input, discarded;
detach;
while true do begin
for i := 1 step 1 until 6 do begin
last_input := inreal; resume printer
end;
discarded := inreal
end
end PRODUCER;
Тело каждого класса начинается с detach, что позволяет главной программе продолжать инициализацию других сопрограмм. Функция inreal возвращает число, прочитанное из входного потока, процедура outreal его печатает, процедура next_line обеспечивает переход на следующую строку ввода.
Сопрограммы хорошо соответствуют другим понятиям ОО-построения ПО. Заметим, насколько децентрализована приведенная схема: каждый процесс занимается своим делом, вмешательство других ограничено. Producer заботится о создании элементов ввода, printer - о выводе, controller - о том, когда начинать и заканчивать. Как обычно, хорошей проверкой качества решения является простота расширения и модификации; здесь явно надо добавить сопрограмму, проверяющую конец ввода (как просит одно из упражнений). Сопрограммы расширяют децентрализацию еще на один шаг, что является признаком хорошей ОО-архитектуры.
Архитектуру можно сделать еще более децентрализованной. В частности, процессы в описанной структуре должны все же активизировать друг друга по имени. В идеале им не нужно ничего знать друг о друге, кроме передаваемой информации (например, принтер получает last_input от producer). Примитивы моделирования, изучаемые далее, позволяют это. После этого решение может использовать полный механизм параллелизма, описанный в одной из лекций. Его независимость от платформы означает, что он будет работать для сопрограмм, так же как истинный параллелизм.
Последовательное выполнение и наследование
Даже если класс Simula не использует механизмы сопрограмм (detach, resume), он помимо компонентов имеет тело (последовательность инструкций) и может вести себя как процесс в дополнение к своей обычной роли реализации АТД. В сочетании с наследованием это свойство ведет к более простой версии того, что в обсуждении параллелизма называлось аномалией наследования. Язык Simula, благодаря ограничениям (наследование единичное, а не множественное; сопрограммы, а не полный параллелизм), способен обеспечить языковое решение проблемы аномалии.
Пусть bodyC - это последовательность инструкций, объявленная как тело C, а actual_bodyC - последовательность инструкций, выполняемая при создании каждого экземпляра C. Если у C нет предка, actual_bodyC - это просто bodyC. Если у C есть родитель A (один, поскольку наследование одиночное), то actual_bodyC - по умолчанию имеет вид:
actual_bodyA; bodyC
Другими словами, тела предков выполняются в порядке наследования. Но эти действия по умолчанию, возможно, не то, что нужно. Для изменения порядка действий, заданных по умолчанию, Simula предлагает инструкцию inner, обозначающую подстановку тела наследника в нужное место тела родителя. Тогда действия по умолчанию эквивалентны тому, что inner стоит в конце тела предка. В общем случае тело A выглядит так:
instructions1; inner; instructions2
Тогда, если предположить, что само A не имеет предка, actual_bodyC имеет вид:
instructions1; bodyC; instructions2
Хотя причины введения подобной семантики ясны, соглашение выглядит довольно неуклюже:

  • во многих случаях потомкам необходимо создать свои экземпляры не так, как их предкам (вспомните POLYGON и RECTANGLE);
  • тела родителей и потомков, как, например C, становится трудно понять: прочтение bodyC еще ничего не говорит о том, что будет делаться при выполнении new;
  • соглашение не переносится естественным образом на множественное наследование (хотя это не прямая забота Simula).

Трудности с inner - типичное следствие активности объектов, о чем говорилось при обсуждении параллелизма.
Почти все ОО-языки после Simula отказались от соглашения inner и рассматривали инициализацию объекта как процедуру.

Моделирование

Верный своему прошлому язык Simula содержит набор примитивов для моделирования дискретных событий. Конечно, неслучайно, что первый ОО-язык создавался для моделирования внешнего мира. Сила объектного подхода проявляется особенно ярко именно в этой области.
Моделирующее ПО анализирует и предсказывает поведение некоторой внешней системы: линии сборки, химической реакции, компьютерной операционной системы.
Особенностью моделирования дискретных событий является то, что внешняя система представлена своими состояниями, способными изменяться в ответ на события, происходящие в дискретные моменты времени. При непрерывном моделировании жизнь системы рассматривается как непрерывный процесс, как непрерывно развивающееся состояние. Какой из подходов является лучшим для данной внешней системы, зависит не столько от природы системы - непрерывной или дискретной (часто такая постановка бессмысленна), сколько от моделей, для нее создаваемых.
Еще одним конкурентом моделирования дискретных событий является аналитическое моделирование, где строится математическая модель внешней системы, а затем решаются соответствующие уравнения. При моделировании дискретных событий для предсказания поведения системы на сколько-нибудь значимом периоде времени приходится увеличивать время моделирования и время работы программной системы. Аналитические методы позволяют получать решение на любой заданный момент времени и, следовательно, более эффективны. Однако, как правило, физические системы слишком сложны, чтобы можно было построить реалистичную математическую модель, допускающую аналитическое решение. Тогда моделирование остается единственной возможностью.
Многие внешние системы естественно укладываются в схему моделирования дискретных событий. Примером может служить линия сборки, где типичные события могут включать появление на линии новых деталей, рабочих или машин, выполняющих определенную операцию над деталями, снятие с линии готового продукта, сбой, приводящий к остановке. Моделирование можно использовать для нахождения ответов на вопросы о моделируемых физических системах. Сколько времени (в среднем, минимально, максимально, среднее отклонение) потребуется для производства конечного продукта? Как долго данный механизм остается неиспользованным? Каков оптимальный уровень запасов?
Исходные данные для моделирования - это последовательность событий и частота их появлений. Данные можно получить с помощью измерений, производимых на внешней системе. Зачастую их получают в соответствии с заданными статистическими законами, генерируя соответствующие последовательности случайных чисел.
При моделировании вводится понятие модельного времени. Его протекание определяет моменты совершения определенных событий, продолжительность выполнения определенной операции на определенной детали. Модельное время не следует путать со временем вычисления. Для моделирующей системы модельное время - это переменная, значение которой в программе дискретно изменяется. Доступный в языке Simula запрос time позволяет в период выполнения системы получать текущее время и управлять временными событиями.
Компонент time и другие компоненты моделирования содержатся в библиотечном классе SIMULATION, он может использоваться как предок любого класса. Будем называть "классом моделирования" любой класс, являющийся потомком SIMULATION.


В Simula наследование можно применять к блокам: блок, написанный в форме: C begin... end имеет доступ ко всем компонентам, объявленным в классе C. Класс SIMULATION часто используется таким образом как родитель всей программы, а не просто класса. Поэтому можно говорить о "моделирующей программе".

Класс SIMULATION содержит объявление класса PROCESS. (Как уже отмечалось, объявления классов в Simula могут быть вложенными.) Его потомки - классы моделирования - могут объявлять потомков PROCESS, их будем называть "классами процессов", а их экземпляры - просто "процессами". Экземпляр PROCESS задает при моделировании процесс внешней системы. Наряду с другими свойствами процессы могут объединяться в связный список (что означает, что PROCESS - это потомок некоторого класса Simula, являющегося эквивалентом класса LINKABLE). Процесс может находиться в одном из четырех состояний:

  • активный - выполняемый в данный момент;
  • приостановленный - ждущий продолжения;
  • бездействующий - холостой, или не являющийся частью системы;
  • завершенный.

Любое моделирование (то есть любой экземпляр потомка SIMULATION) поддерживает список событий (event list), содержащий уведомления о событиях (event notices). Каждое уведомление - это пара <process, activation_time>, где activation_time означает время активизации процесса process. (Здесь и далее любое упоминание о времени, так же как слова "когда" или "в настоящее время", относится к модельному времени - времени внешней системы, доступному через time.) Список событий сортируется по возрастанию activation_time; первый процесс активный, все остальные приостановлены. Незавершенные процессы, которых нет в списке, являются бездействующими.
Основная операция над процессами - активизация, она планирует активизацию процесса в определенное время, помещая уведомление о событии в список событий. Видимо по синтаксическим причинам эта операция не является вызовом процедуры класса SIMULATION, а специальной инструкцией, использующей ключевое слово activate или reactivate. (Вызов процедуры был бы более согласованным подходом, тем более что фактически стандарт определяет семантику activate в процедурных терминах.) Основная форма инструкции такова:
activate some_process scheduling_clause
где some_process - непустая сущность типа PROCESS. Необязательный параметр scheduling_clause задается одной из следующих форм:
at some_time
delay some_period
before another_process
after another_process
Первые две формы указывают на позицию нового уведомления о событии, задавая время его активизации, вычисляемое как max (time, some_time) для формы at и max (time, time + some_period) в форме delay. Новое уведомление о событии будет внесено в список событий после любого другого события, уже находящегося в перечне с меньшим или таким же временем активизации, если оно не помечено prior. Последние две формы определяют позицию по отношению к другому процессу в перечне. Отсутствие scheduling_clause эквивалентно delay 0.
Процесс может активизировать себя в более позднее время, указав себя как целевой процесс - some_process. В этом случае ключевое слово должно быть reactivate. Это полезно при запуске задачи внешней системы, требующей на свое выполнение некоторого модельного времени. Если запускается задача, решение которой занимает 3 минуты (180 сек.), то для соответствующего исполнителя - процесса worker - можно задать инструкцию:
reactivate worker delay 180
Эта ситуация настолько типична, что для нее введен специальный синтаксис, позволяющий избежать явного вызова самого себя:
hold (180)
с точно тем же эффектом.
Вы, вероятно, уже догадались, что процессы реализуются как сопрограммы. Примитивы моделирования внутренне используют рассмотренные выше примитивы сопрограмм. Эффект hold (some_period) можно приблизительно описать (в синтаксисе, похожем на нотацию этой книги, но с расширением resume) как:
-- Вставка нового уведомления о событии в список событий в требуемую позицию:
my_new_time := max (time, time + some_period)
create my_reactivation_notice.make (Current, my_new_time)
event_list.put (my_reactivation_notice)
-- Получить первый элемент списка событий и удалить его:
next := event_list.first; event_list.remove_first
-- Активизировать выбранный процесс, изменяя время при необходимости:
time := time.max (next.when); resume next.what
предполагая следующие объявления:
my_new_time: REAL; my_reactivation_notice, next: EVENT_NOTICE
class EVENT_NOTICE creation make feature
when: REAL - т.е. время
what: PROCESS
make (t: REAL; p: PROCESS) is
do when := t; what := p end
end
Если процесс приостанавливается, задавая время своей последующей активизации, то выполнение продолжает приостановленный процесс с наиболее ранним временем активизации. Если указанное время активизации этого процесса позже текущего времени, то соответственно изменяется (увеличивается) текущее время.
Примитивы моделирования, хотя они и основаны на примитивах сопрограмм, принадлежат к более высокому уровню абстракции, потому лучше использовать их, а не полагаться непосредственно на механизмы сопрограмм. В частности, можно рассматривать hold (0) как форму resume, благодаря которой можно не определять явным образом процесс для продолжения, а поручить его выбор механизму списка событий.
Пример моделирования
Классы процессов и примитивы моделирования дают элегантный механизм моделирования процессов внешнего мира. Рассмотрим в качестве иллюстрации исполнителя, которому предлагается выполнять одну из двух задач. Обе требуют некоторого времени; вторая требует включения машины m, работающей 5 минут, и ожидания, пока машина выполнит свою работу.
PROCESS class WORKER begin
while true do begin
"Получить следующую задачу типа i и время ее выполнения d";
if i = 2 then
activate m delay 300; reactivate this WORKER after m;
end;
hold (d)
end while
end WORKER
Операция "получить тип и продолжительность следующей задачи" обычно получает запрашиваемые величины от генератора псевдослучайных чисел, используя определенное статистическое распределение. Библиотека Simula включает ряд генераторов для типичных законов распределения. Предполагается, что в данном примере m - это экземпляр некоторого класса процесса MACHINE, представляющий поведение машин. Все действующие субъекты моделирования равным образом представляются классами процессов.
Simula: оценка
Как и Algol 60, язык Simula знаменателен не столько своим коммерческим успехом, сколько интеллектуальным влиянием. Это очевидно и в теории (абстрактные типы данных), и в практике, где большинство языковых разработок последних двух десятилетий является его потомками - либо детьми, либо внуками его идей. Большой коммерческий успех не пришел по ряду причин, но самая важная и очевидная, заслуживающая лишь сожаления, состоит в том что, как и многие значительные изобретения до него, Simula опередил свое время. Хотя многие сразу увидели потенциальную ценность его идей, в целом программистское сообщество не было к нему готово.
Спустя тридцать лет, как ясно из предыдущего описания, многие идеи языка все еще остаются актуальными.

 

 
На главную | Содержание | < Назад....Вперёд >
С вопросами и предложениями можно обращаться по nicivas@bk.ru. 2013 г.Яндекс.Метрика