Статья представляет собой очень краткое введение в Simula.
Simula ((SIMIUlation LAnguage) ), первый язык программирования с классами и объектами, незаслуженно почти забытый, но из которого выросло современное ООП в том виде, в котором оно присутствует в нашем коде. Это язык для имитационного моделирования реальности. Разработчики новых языков программирования «оглядывались» на Simula при добавлении механизмов объектно-ориентированного программирования в свой язык. Однако Simula упоминается настолько редко, что в русской википедии на момент публикации был только хеллоуворд, а в сети куча устаревших ссылок.
Бьерн Страуструп, говоря о причинах создания C++, сказал так: «Этот язык возник потому, что автору потребовалось написать программы моделирования, управляемые прерываниями. Язык SIMULA-67 идеально подходит для этого, если не учитывать эффективность.»
История
На самом деле языку больше 50 лет. Первая версия, известная как Simula I, появилась в 1964 — 1965 годах. Она была расширением языка Алгол-60 (а точнее препроцессором). Авторы языка — норвежские ученые Кристен Нюгор и Оле-Йохан Даль. Первые версии языка работали на 36-битных компьютерах UNIVAC 1107.
Уже в 1967 году вышла Simula-67, которую и называют сейчас просто Simula.
В нашей стране первую версию языка запускали на компьютере Урал-16.
В 1968 году стандарт языка официально заморожен.
Язык распространяется в 70-х годах прошлого столетия, но затем его известность угасает.
Причин такого падения популярности перечисляют несколько, но говоря современным языком — недостаток маркетинга (медленно развивающийся продукт, цена, слабый PR)
Установка
Тренироваться мы будем с помощью GNU Cim, который на самом деле представляет собой компилятор кода Simula в язык С.
Установка на Linux
$ wget http://simula67.at.ifi.uio.no/Cim/cim-3.37.tar.gz
$ tar -xf cim-3.37.tar.gz
$ cd cim-3.37
$ ./configure
$ make
$ sudo make install
$ sudo ldconfig /usr/local/lib
Установка на Mac
$ wget http://simula67.at.ifi.uio.no/Cim/cim-3.37.tar.gz
$ tar -xf cim-3.37.tar.gz
$ cd cim-3.37
$ CFLAGS='-O0 -m32' ./configure
$ make
$ sudo make install
Установка для Windows
Скачайте программу с сайта http://folk.uio.no/simula67/cim.shtml
Hello world!
Пишем в блокноте программу:
Begin
OutText ("Hello World!");
Outimage;
End;
Сохраняем ее под именем test1.cim
Потом делаем так (вариант Linux):
cim test1.cim
./test1
И получаем долгожданное
Hello World!
Как видно из синтаксиса — классический Алгол 60. У большинства вопросов по этому коду не будет, благо в нашей стране в качестве основного языка для обучения используют его потомка Pascal, который внешне не сильно отличается.
Классы объектов
Begin
Class Rectangle (Width, Height); Real Width, Height;
Begin
Real Area, Perimeter;
Procedure Update;
Begin
Area := Width * Height;
OutText("Rectangle is updating, Area = "); OutFix(Area,2,8); OutImage;
Perimeter := 2*(Width + Height);
OutText("Rectangle is updating, Perimeter = "); OutFix(Perimeter,2,8); OutImage;
End of Update;
Update;
OutText("Rectangle created: "); OutFix(Width,2,6);
OutFix(Height,2,6); OutImage;
End of Rectangle;
Ref(Rectangle) R;
R :- New Rectangle(50, 40);
End;
Результат:
Rectangle is updating, Area = 2000.00
Rectangle is updating, Perimeter = 180.00
Rectangle created: 50.00 40.00
Внутри основной процедуры мы создали класс Rectangle с двумя параметрами Width и Height, типа Real — т.е. вещественные числа. По современному это параметры конструктора — но они существуют не только в момент создания объекта, но и при его существовании. Кроме того, мы добавили аттрибуты Area и Perimeter того же типа. Как мы видим, они вычисляются при вызове процедуры Update. Так как эта процедура объявлена внутри класса — она становится методом. То, что идет ниже аттрибутов и методов называется жизнью или телом (Life, Body) объекта.
Т.е. собственно это тот код, который вызывается при создании нового объекта. «Ref(Rectangle) R;» означает объявление переменной R класса Rectangle. В следующей строке идет инициализация этой переменной.
Обратите внимание на вызов OutText внутри процедуры Update — чем не аналог static метода в Java?
Теперь давайте глянем на наследование
Begin
Class Rectangle (Width, Height); Real Width, Height;
Begin
Real Area, Perimeter;
Procedure Update;
Begin
Area := Width * Height;
OutText("Rectangle is updating, Area = "); OutFix(Area,2,8); OutImage;
Perimeter := 2*(Width + Height);
OutText("Rectangle is updating, Perimeter = "); OutFix(Perimeter,2,8); OutImage;
End of Update;
Update;
OutText("Rectangle created: "); OutFix(Width,2,6);
OutFix(Height,2,6); OutImage;
End of Rectangle;
Rectangle Class ColouredRectangle (Color); Text Color;
Begin
OutText("ColouredRectangle created, color = "); OutText(Color);
OutImage;
End of ColouredRectangle;
Ref(Rectangle) Cr;
Cr :- New ColouredRectangle(10, 20, "Green");
End;
Результат:
Rectangle is updating, Area = 200.00
Rectangle is updating, Perimeter = 60.00
Rectangle created: 10.00 20.00
ColouredRectangle created, color = Green
Как видно из примера, подкласс определяется как обычный класс, но с префиксом названия класса родителя.
Причем нужно указать только дополнительные параметры. Параметры, которые были у родителя, добавятся автоматически.
Как видно, при создании объекта нужно перечислить все параметры — сначала родителя, потом потомка.
Симуляция реального мира
Теперь давайте что нибудь «просимулируем». Все-таки этот язык создавался изначально для моделирования объектов реального мира.
Смоделируем работу пешеходного светофора. Светофор имеет только два состояния. Каждую минуту к переходу подходит новый человек и, в зависимости от состояния светофора, либо переходит улицу, либо ждет.
Simulation Begin
Procedure report (message); Text message; Begin
OutFix (Time, 2, 0); OutText (": " & message); OutImage;
End;
Integer u;
Ref (Semaphor) s;
Integer i;
Process Class Semaphor; Begin
Boolean isRed;
Ref (Head) waitingPersons;
waitingPersons:- New Head;
isRed := false;
report ("GREEN ON");
While True Do Begin
Hold (2.3);
isRed := true;
report ("RED ON");
Hold (4.25);
isRed := false;
report ("GREEN ON");
While not s.waitingPersons.Empty Do Begin
Activate s.waitingPersons.First;
s.waitingPersons.First.Out;
End;
End;
End;
Process Class Person (pid); Integer pid; Begin
OutFix (Time, 2, 0); OutText (" Peson "); OutInt(pid, 3); OutText (" is near the crossover."); OutImage;
If s.isRed Then Begin
Wait (s.waitingPersons);
End;
OutFix (Time, 2, 0); OutText (" Peson "); OutInt(pid, 3); OutText (" is going."); OutImage;
End;
Process Class PersonGenerator; Begin
While True Do Begin
i := i + 1;
Hold (1);
Activate new Person(i);
End;
End;
s:- New Semaphor;
i := 0;
Activate s;
Activate New PersonGenerator;
Hold (20);
End;
Результат:
0.00: GREEN ON
1.00 Peson 1 is near the crossover.
1.00 Peson 1 is going.
2.00 Peson 2 is near the crossover.
2.00 Peson 2 is going.
2.30: RED ON
3.00 Peson 3 is near the crossover.
4.00 Peson 4 is near the crossover.
5.00 Peson 5 is near the crossover.
6.00 Peson 6 is near the crossover.
6.55: GREEN ON
6.55 Peson 3 is going.
6.55 Peson 4 is going.
6.55 Peson 5 is going.
6.55 Peson 6 is going.
7.00 Peson 7 is near the crossover.
7.00 Peson 7 is going.
8.00 Peson 8 is near the crossover.
8.00 Peson 8 is going.
8.85: RED ON
9.00 Peson 9 is near the crossover.
10.00 Peson 10 is near the crossover.
11.00 Peson 11 is near the crossover.
12.00 Peson 12 is near the crossover.
13.00 Peson 13 is near the crossover.
13.10: GREEN ON
13.10 Peson 9 is going.
13.10 Peson 10 is going.
13.10 Peson 11 is going.
13.10 Peson 12 is going.
13.10 Peson 13 is going.
14.00 Peson 14 is near the crossover.
14.00 Peson 14 is going.
15.00 Peson 15 is near the crossover.
15.00 Peson 15 is going.
15.40: RED ON
16.00 Peson 16 is near the crossover.
17.00 Peson 17 is near the crossover.
18.00 Peson 18 is near the crossover.
19.00 Peson 19 is near the crossover.
19.65: GREEN ON
19.65 Peson 16 is going.
19.65 Peson 17 is going.
19.65 Peson 18 is going.
19.65 Peson 19 is going.
Главная процедура начинается с Simulation. Общее время симуляции — 20 минут. Процедура report вспомогательная, осуществляет вывод данных с текущим значением времени симуляции. Светофор Semaphor в статусе «зеленый» находится 2.3 минуты, в статусе «красный» — 4.25 минуты. Состояние задает переменная isRed. Очередь waitingPersons — это пешеходы, которые не смогли сразу перейти улицу так как был красный светофор.
PersonGenerator — это генератор пешеходов — каждую минуту новый пешеход подходит к светофору. Hold выполняет роль хода времени симуляции.
Process — предок всех классов «активных» участников данного моделирования.
Как мы видим, код достаточно интуитивен и не сложен, простую имитацию можно сделать без очень глубокого погружения в язык.
Изучая старые языки программирования можно узнать происхождение многих вещей в современных языках. В данном случае поражает насколько Simula опередила свое время если учесть компьютеры, на которых она работала. Не скажу, что имеет смысл писать на этом языке код. Потому что не все примеры даже с англоязычной вики работают с первого раза. В частности, возникли сложности с виртуальными методами — хотя это скорее всего связано с конкретным компилятором. Но для задач обучения и для простого имитационного моделирования Simula мне показалось достаточно удобной.
Полезные ссылки:
1. Установка для Linux, Mac, Windows
2. Введение в ООП от University of Malta, причем есть даже перевод на русский
3. Статья аж самого Кнута
4. Сайт с большим количеством работающих ссылок
Автор: nemavasi