...

вторник, 2 января 2018 г.

Simula — 50 лет ООП

Статья представляет собой очень краткое введение в Simula.

Simula ((SIMIUlation LAnguage) ), первый язык программирования с классами и объектами, незаслуженно почти забытый, но из которого выросло современное ООП в том виде, в котором оно присутствует в нашем коде. Это язык для имитационного моделирования реальности. Разработчики новых языков программирования «оглядывались» на Simula при добавлении механизмов объектно-ориентированного программирования в свой язык. Однако Simula упоминается настолько редко, что в русской википедии на момент публикации был только хеллоуворд, а в сети куча устаревших ссылок.

Бьерн Страуструп, говоря о причинах создания C++, сказал так: «Этот язык возник потому, что автору потребовалось написать программы моделирования, управляемые прерываниями. Язык SIMULA-67 идеально подходит для этого, если не учитывать эффективность.»

Зачем мне это

Меня привели к Simula static методы в Java. А еще точнее, все началось с просмотра доклада Егора Бугаенко, который называет static методы злом в Java. Если коротко, по его мнению они вносят в Java элементы процедурного программирования, ломая ООП. Соответсвенно, возник вопрос — а почему эти методы появились в языке Java — чем руководствовались создатели языка? Ища ответ на этот, вопрос докопался до Smalltalk (1971 год), с которого (чего уж греха таить) было взято ООП в Java. Как оказалось, static методы были и там, только называются они методами класса. Но Smalltalk тоже возник не из воздуха. Его предшественником была Simula (1965 год). Как оказалось, подобные методы в были и там. Конечно назывались они тоже по-другому. В частности, встречал название «свободный блок». А «свободные блоки» — это обычные процедуры. Ведь предком Simula был Алгол 60. А первые версии Simula представляли собой «надстройку» над Алголом 60.


История


На самом деле языку больше 50 лет. Первая версия, известная как Simula I, появилась в 1964 — 1965 годах. Она была расширением языка Алгол-60 (а точнее препроцессором). Авторы языка — норвежские ученые Кристен Нюгор и Оле-Йохан Даль. Первые версии языка работали на 36-битных компьютерах UNIVAC 1107.

Уже в 1967 году вышла Simula-67, которую и называют сейчас просто Simula.
В нашей стране первую версию языка запускали на компьютере Урал-16.
В 1968 году стандарт языка официально заморожен.

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

Установка


Тренироваться мы будем с помощью GNU Cim, который на самом деле представляет собой компилятор кода Simula в язык С.

Установка на Linux

$ wget http://ift.tt/2EuYShi
$ tar -xf cim-3.37.tar.gz
$ cd cim-3.37
$ ./configure
$ make
$ sudo make install
$ sudo ldconfig /usr/local/lib

Установка на Mac
$ wget http://ift.tt/2EuYShi
$ tar -xf cim-3.37.tar.gz
$ cd cim-3.37
$ CFLAGS='-O0 -m32' ./configure
$ make
$ sudo make install

Установка для Windows
Скачайте программу с сайта http://ift.tt/2DKzi6F

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. Сайт с большим количеством работающих ссылок

Let's block ads! (Why?)

Комментариев нет:

Отправить комментарий