ООП по Вирту
Главная     ◄Глагол     Азбука ►   Задачи на Глаголе ►   Примеры приложений ►   Среда разработки ►   Отладка программ ►   Отличия от Оберона ►   Отличия от Паскаля ►   Ассемблер ARM ►   Глагол для ARM ►   ? и Ответы
 

Взгляд Н.Вирта на ООП в языке Оберон (1988-1990)


Аз да буки, да и конец науки

 
 

Отличия ООП в Обероне от C++

1. Без описателей классов, вроде «class» или «object».

В языке Оберон нет отдельного ключевого слова для описания классов, вроде «class» или «object», сочтено, что обычного понятия «тип запись» вполне достаточно. По сути, каждый тип запись — это описание класса, а поля записи — это данные-члены или свойства класса.

2. Без методов (процедур и функций, связанных с классом).

В исходном Обероне методов (процедур и функций, связанных с классом) нет вообще. Механизм методов может быть использован путём объявления в записи полей процедурного типа, которым при создании экземпляра класса [объекта] присваиваются имена конкретных процедур, т.е. имеем динамически назначаемые методы для разных экземпляров «типа запись» [объектов класса] (такого в C++ нету, там методы статические, т.е. применяемые для всех экземпляров класса). Вызов таких методов-процедур производится традиционным способом обращения к полю записи. По умолчанию метод-процедура не знает об экземпляре класса [объекте], для которого она была вызвана (в Обероне нет механизма, аналогичного this в C++/Java или SELF в Pascal-подобных языках), и если такие сведения ей необходимы, ссылка на экземпляр [объект] должна быть передана явно (например, через фактический параметр/источник).

NB: Отсутствие явно описываемых методов (связанных с классом) было одним из качеств исходного Оберона (1988-1990), вызвавшего критику программистов, привыкших к традиционным гибридным ЯП с ООП (C++/Java).

С другой стороны, предлагаемый Обероном механизм позволяет реализовать всё, что реализуемо традиционными средствами языков с методами, и даже более того — в Обероне каждый экземпляр записи [объект] может иметь свой собственный вариант метода (т.е. разные значение поля процедурного типа — это динамические методы для экземпляров [объектов] или гетерогенность по типу поля-процедуры в записи), тогда как при описании методов внутри класса (т.е. вложенных в скобки «class»..«end») в традиционных гибридных ЯП с ООП, все экземпляры [объекты] работают только с одним [статическим] вариантом метода (C++/Java).

В Обероне-2 (1992-1996) методы [классов] всё-таки были введены (это методы-процедуры, связанные с типом запись). Однако, в отличии от С++, в Оберон-2 методы, связанные с типом запись, описываются отдельно от (за пределами) описания типа запись, но с указанием в скобках после имени (типа), с которым они связаны.

3. Вместо наследования [inheritance] — расширение записей.

Парадигма [от греч. παράδειγμα, «модель, образец»] объектно-ориентированного программирования (ООП) поддерживается механизмом расширения записей.

Новый тип запись в классическом Обероне может быть объявлен как расширение существующего. В этом случае тип, который расширяется, указывается в описании записи в скобках после ключевого слова RECORD. Расширенный тип автоматически получает все поля расширяемого типа (а в Обероне-2 ещё и связывается со всеми процедурами, которые связаны с базовым/опорным, т.е. расширяемым, типом запись). Процедуры, связанные с новым типом, могут иметь ту же сигнатуру (т.е. имя и параметры), что и процедуры, связанные с расширяемым (т.е. базовым/опорным) типом — таким образом обеспечивается переопределение (виртуализация) методов в порождённых типах (в расширенных записях).

В Компонентном Паскале (1997) по умолчанию записи, с целью более полного контроля за расширяемостью типов, не являются расширяемыми, а методы не могут быть переопределены (т.е. быть виртуальными). Чтобы разрешить расширение записей и переопределение методов, используются специально введённые ключевые слова EXTENSIBLE (расширяемый), ABSTRACT (абстрактный — память не выделяется), LIMITED (ограниченный), EMPTY (абстрактный и без полей-свойств), NEW, IN, OUT.

Специфика ООП в Обероне

Особенность языка состоит в механизме наследования через тип RECORD, а не через модуль (в C++ это структурный тип «class»). Такой механизм позволяет более аккуратно управлять областью видимости: несколько RECORD-классов можно включать в капсулу одного модуля, что дает возможность получать доступ к деталям реализации соседей без нарушения принципа сокрытия информации и без лишних накладных расходов. Методы в Обероне представляются полями процедурных типов (процедурные типы Оберона взяты в C# за основу представления делегатов).

Не нужны пространства имен (как в C++/C#) — вместо этого есть восходящая к Дэвиду Парнасу четкая концепция модуля, оперирующего понятием экспорта-импорта сущностей языка (константы, типы, поля типов, переменные, процедуры).

Модули поддерживают полноценную раздельную компиляцию (интерфейсная часть извлекается автоматически по имеющейся маркировке экспорта), являются единицей загрузки и основой построения программных компонентов.

Парадигма компонентного программирования в Обероне

4. Инкапсуляция (упрятывание, сокрытие) — на уровне модуля (а не записи или класса).

Оберон нацелен на компонентно-ориентированную разработку программного обеспечения (компонента — группа модулей). Упрятывание (инкапсуляция) данных и методов поддерживается исключительно на уровне модуля (а не записи или класса) — все типы, объявленные внутри модуля, друг для друга абсолютно прозрачны. Из других модулей доступно то, что объявлено при определении как экспортируемое.

5. Полиморфизм (многоформие, много тел) — переопределение (виртуализация) методов-процедур.

Полиморфизм [polymorphism] («один интерфейс — много реализаций») обеспечивается за счёт механизма методов. И процедурные поля в Обероне, и методы в Обероне-2 ведут себя как виртуальные в терминологии большинства гибридных ЯП с ООП (C++/Java). Полиморфизм методов обеспечивается также при помощи расширенной конструкции WITH, позволяющей выполнять различные группы операторов (тел) в зависимости от того, к какому [уровню] расширения типа запись относится её аргумент (в Обероне-07/2007..2016 нет WITH, однако переопределение методов присутствует).

В языке отсутствует специальный механизм конструкторов. Рекомендуемым методом создания и инициализации объектов (экземпляров записи) является описание порождающих модулей и процедур (в традиционной терминологии ООП — factory /паттерн-фабрика/).

6. Постоянные объекты в оберон-среде выполнения приложения.

Программа (приложение Windows) в компонентной парадигме представляет собой набор относительно самостоятельных компонентов (в данном случае — модулей), имеющих скрытую от внешнего мира внутреннюю структуру и чётко определённый интерфейс. Модули могут загружаться и выгружаться динамически, во время работы программы [это относится только к Oberon-реализациям Вирта и к BlackBox, но не обязательно присутствует в сторонних Оберон-реализациях для Windows, таких как XDS , GNU Oberon-2 , Оберон-2 , gpCP , Oberon-07M , Oberon07ru , AyaCompiler /Oberon07 x64/]. Оберон-среда, предоставляет развитые средства контроля типов во время выполнения (!), которые позволяют писать универсальные алгоритмы обработки данных, не зависящие от конкретных типов этих данных (например, библиотека для работы с СУБД может предоставлять методы, записывающие результат запроса из базы в запись произвольной структуры, если набор и типы полей этой записи соответствуют набору и типам полей в БД).

В компонентной парадигме считается неудачным архитектурное решение, связанное с широким использованием наследования (расширения) от типов, объявленных в другой компоненте, поскольку это приводит к явлению, известному как «хрупкость базового типа» — после того, как от базового типа порождено большое количество типов-наследников [расширенных типов] (причём часть из них может быть даже НЕизвестна разработчику базового типа), любые изменения в реализации базового типа становятся крайне рискованными, так как они могут непредсказуемым образом отразиться на типах-потомках.

Известно, что одной из проблем применения ООП в системном программировании [т.е. при проектировании ОС] является необходимость иметь группы маленьких классов, которые могли бы взаимодействовать без дополнительных накладных расходов. В Обероне этой проблемы нет — все типы, определённые в одном модуле, видят друг друга, а проблем с надёжностью это не создаёт, так как модуль всё равно разрабатывается, тестируется и сопровождается как единое целое.

Типичное приложение, разработанноя на Обероне, представляет собой набор модулей с процедурными интерфейсами, через которые модули обмениваются данными, в том числе и объектами. При этом все средства инкапсуляции (упрятывания) действуют только в межмодульном взаимодействии, что делает удобным системное программирование с использованием объектов.

Объектно-ориентированное программирование по Вирту

7. ООП в Обероне подчинена концепции модульности.

Средства объектного программирования интерпретируются в Обероне как естественное развитие средств работы с записями в модульной системе, точнее, как технический инструментарий для решения конкретной архитектурной задачи: обеспечить эффективное «разделение труда» между различными модулями при работе с динамическими типами и структурами данных: например, работа с указателями в списке может быть скрыта (вместе с соответствующими полями) в одном модуле, а определение и работа с конкретным «наполнением» элементов списка — задаваться в другом (или, чаще, в других). В этом смысле технология объектного программирования в Обероне подчинена концепции модульности: она здесь является, скорее, средством описания данных, чем средством построения архитектуры приложения в целом.

Oberon SA

Oberon SA — это версия языка Оберон, разработанная Н.Виртом для процессора Strong-ARM, используемого в беспилотном вертолёте.

На основе опыта разработки Oberon SA Н.Вирт в 2007 году подготовил изменения и дополнения к классическому Оберону для более строгой поддержки структурного программирования, чем [имеющиеся], например, в Oberon-2 или Компонентном Паскале. Новая версия языка получила название Oberon-07. Имеется перевод «The Programming Language Oberon, Revision 1.11.2008» на русский язык, cкачать.

Но в отношении поддержки объектно-ориентированного программирования ЯП Oberon-07 не следует за Обероном-2, а продолжает минималистичную линию классического Оберона (1988-1990), включая отсутствие поддержки процедур, привязанных к типу запись [классу].

Oberon-07

(rev.2007..20011..2013..2016 Н.Вирта).

Oberon-07 имеет следующие основные отличия от классического Оберона (1988-1990):

  • в цикле WHILE разрешены несколько охраняемых ветвей (ELSIFDO). Тем самым обеспечена полная явная поддержка цикла Дейкстры. Ранее цикл Дейкстры моделировался при помощи цикла LOOP;
  • соответственно, исключён неструктурированный цикл LOOP вместе с оператором EXIT (выход из цикла);
  • в процедуре теперь может быть только одна точка выхода, фиксированная в конце тела процедуры [RETURN x END F;]. В сущности, RETURN перестал быть оператором, превратившись в такую же синтаксическую часть описания процедуры, как и само ключевое слово PROCEDURE и т. д.;
  • добавлен оператор цикла FOR;
  • исключён оператор WITH, хотя переопределение методов осталось: IF..IS..THEN..ELSIF..IS..THEN..ELSE..END;
  • исключено неявное приведение типа INTEGER к REAL и типов с различной разрядностью друг к другу (из числовых типов остались только INTEGER, LONGINT и REAL);
  • разрешены ссылки только на записи (а открытые массивы допустимы только как формальные параметры/приёмники в процедурах);
  • уточнено правило импорта/экспорта: экспорт переменных разрешён только для чтения, спецификатор экспорта один — «*»;
  • уточнены типы данных — CHAR поддерживает множество Latin-1, INTEGER — [−2^31 ... +2^31-1], REAL — IEEE Standard 64 бита (а не 32 и, соотвественно, упразднён LONGREAL — IEEE Standard 64 бита), SET — множество целых между 0 и 31.

Австралийская компания CFB Software (г. Брисбен) при Университете штата Квинсленд разработала IDE Astrobe для языка Oberon-07 для микроконтроллеров ARM7 компании NXP (Philips) и синтаксические диаграммы языка Oberon-07, а также рекомендации по стилю программ на Oberon-07.


Примеры компонент с ООП на Обероне-07:


Шаблон-1\Pattern-1.
Динамическая рассылка осуществляется путём переопределения абстрактных методов-процедур
из модуля Figures в реальные методы расширенной записи (у потомка).


MODULE Figures;         (* Модуль с описаниями абстрактных записей - классов объектов или предметов *)
TYPE
   Figure*    = POINTER TO FigureDesc;
   Interface* = POINTER TO InterfaceDesc;
(* Описание НЕ абстрактного типа запись InterfaceDesc - класса объектов или предмета *)
                          InterfaceDesc* = RECORD
      draw*  : PROCEDURE (f:Figure);         (* Описание процедурных полей с малой (строчной) буквы *)
      clear* : PROCEDURE (f:Figure);
      mark*  : PROCEDURE (f:Figure);
      move*  : PROCEDURE (f:Figure; dx, dy : INTEGER);
                          END;
(* Описание абстрактного типа запись FigureDesc - базового\опорного класса объектов или предмета *)
                          FigureDesc* = RECORD
          if : Interface;
                          END;

PROCEDURE Init* (f:Figure; if : Interface);
BEGIN
   f.if := if;
END Init;
                            (* ----------- абстрактные методы-процедуры называются с заглавной буквы *)
PROCEDURE Draw* (f:Figure);
BEGIN
   f.if.draw(f);
END Draw;
                                 (* Прочие абстрактные методы-процедуры здесь *)
PROCEDURE Clear* (f:Figure);
BEGIN
   f.if.clear(f);
END Clear;

PROCEDURE Mark* (f:Figure);
BEGIN
   f.if.mark(f);
END Mark;

PROCEDURE Move* (f:Figure; dx, dy : INTEGER);
BEGIN
   f.if.move(f, dx,dy);
END Move;

END Figures.

Шаблон-1\Pattern-1. Продолжение.
Расширение абстрактного\опорного типа Figure до определенной формы (Rectangle):
We extend the generic type Figure to a specific shape:


MODULE Rectangles;       (* Модуль с описаниями реальных записей-классов, объекты которых создаются *)
IMPORT Figures;
TYPE
   Rectangle* = POINTER TO RectangleDesc; (* Описание реального класса Прямоугольник -
                                потомка\наследника абстрактного класса Фигура *)
                           RectangleDesc* = RECORD(Figures.FigureDesc)
     x, y, w, h : INTEGER;
                           END;
VAR
   if : Figures.Interface;
                                                          (* Конструктор объекта r:Rectangle *)
PROCEDURE New* (VAR r : Rectangle);
BEGIN
   NEW(r);                                            (* Выделить память объекту r:Rectangle *)
   Figures.Init(r, if);                       (* Инициализация поля   r.if:Figures.Interface *)
END New;
                             (* ----------- реальные методы-процедуры называются с заглавной буквы *)
PROCEDURE Draw* (f:Figure);  (* переопределение Draw() из модуля Figures *)
  VAR
    r : Rectangle;
BEGIN
   r:=f(Rectangle);    (* указатель на объект f:Figure преобразуется в указатель r:Rectangle *)
  (* ... *)
END Draw;
                                  (* Прочие реальные методы-процедуры здесь *)
PROCEDURE Clear* (f:Figure); (* переопределение Clear() из модуля Figures *)
  VAR
    r : Rectangle;
BEGIN
   r:=f(Rectangle);    (* указатель на объект f:Figure преобразуется в указатель r:Rectangle *)
  (* ... *)
END Clear;

PROCEDURE Mark* (f:Figure);  (* переопределение Mark() из модуля Figures *)
  VAR
    r : Rectangle;
BEGIN
   r:=f(Rectangle);    (* указатель на объект f:Figure преобразуется в указатель r:Rectangle *)
  (* ... *)
END Mark;

PROCEDURE Move* (f:Figure; dx, dy : INTEGER); (* переопределение Move() из модуля Figures *)
  VAR
    r : Rectangle;
BEGIN
   r:=f(Rectangle);    (* указатель на объект f:Figure преобразуется в указатель r:Rectangle *)
  (* ... *)
END Move;

BEGIN                (* Инициализация модуля Rectangles. *)
                         (* Конструктор объекта if:Figures.Interface *)
   NEW(if);          (* Выделить память объекту if:Figures.Interface *)
                     (* Инициализация процедурных полей реальными методами с заглавной буквы *)
   if.draw  := Rectangles.Draw;
   if.clear := Rectangles.Clear;
   if.mark  := Rectangles.Mark;
   if.move  := Rectangles.Move;
END Rectangles.


Шаблон-2\Pattern-2.
Динамическая рассылка осуществляется только с помощью отдельных процедур (не методов),
типы которых описанны в модуле Figures, это общий модуль.
Dynamic dispatch is only done via procedures in Figures module that is the generic module.


Этот Шаблон-2\Pattern-2 состоит в замене методов-процедур в виде полей записи на отдельные процедуры (не связанные с типом запись), вызов которых происходит по условию вида IF..IS..THEN..ELSIF..IS..THEN..ELSE..END (переключается/дискриминирует между вызовами отдельных процедур):

This technique consists of replacing the set of methods with a single procedure, which discriminates among the various methods:

MODULE Figures;         (* Модуль с описаниями абстрактных записей - классов объектов или предметов *)
TYPE
   Figure*    = POINTER TO FigureDesc;
(* Описание типов записей, поля которых соответствуют списку приёмников (формальных параметров)
                         в отдельных процедурах, вызываемых вместо методов для объекта f:Figure *)
   Message*   = RECORD END;
   DrawMsg*   = RECORD (Message) END;
   ClearMsg*  = RECORD (Message) END;
   MarkMsg*   = RECORD (Message) END;
   MoveMsg*   = RECORD (Message) dx*, dy* : INTEGER END;
(* Описание типа процедура - абстрактного метода для объекта f:Figure *)
   Handler*   = PROCEDURE (f:Figure; VAR msg : Message);
(* Описание абстрактного типа запись - базового\опорного класса объектов или предмета *)
   FigureDesc* = RECORD
      handle : Handler;     (* Описание скрытого процедурного поля с малой (строчной) буквы *)
   END;

PROCEDURE Init* (f:Figure; handle : Handler);
BEGIN
  f.handle := handle; (* инициализация скрытого процедурного поля записи  f.handle() *)
END Init;
                            (* ----------- абстрактный метод-процедура называется с заглавной буквы *)
PROCEDURE Handle* (f:Figure;
             VAR msg:Figures.Message);
BEGIN
   f.handle(f, msg);                 (* скрытое процедурное поле записи  f.handle() *)
END Handle;

END Figures.

Шаблон-2\Pattern-2. Продолжение.
Расширение абстрактного\опорного типа Figure до определенной формы (Rectangle):
We extend the generic type Figure to a specific shape:


MODULE Rectangles;       (* Модуль с описаниями реальных записей-классов, объекты которых создаются *)
IMPORT Figures;
TYPE
   Rectangle* = POINTER TO RectangleDesc;
                           RectangleDesc* = RECORD(Figures.FigureDesc)
      x, y, w, h : INTEGER;
                           END;
                               (* ----- реальные процедуры (не методы) называются с заглавной буквы *)
PROCEDURE Draw* (r:Rectangle);
BEGIN
  (* ... *)
END Draw;
                              (* Прочие реальные процедуры (не методы) здесь *)
PROCEDURE Clear* (r:Rectangle);
BEGIN
  (* ... *)
END Clear;

PROCEDURE Mark* (r:Rectangle);
BEGIN
  (* ... *)
END Mark;

PROCEDURE Move* (r:Rectangle; dx, dy : INTEGER);
BEGIN
  (* ... *)
END Move;
                               (* ---------- реальный метод-процедура называется с заглавной буквы *)
PROCEDURE Handle* (f:Figure;               (* переопределение абстрактного метода Figures.Handle() *)
             VAR msg:Figures.Message);     (* переменная типа запись - опорная или её потомок,
                                        содержащая список приёмников (формальные параметры) метода *)
   VAR
      r : Rectangle;
BEGIN
     r:=f(Rectangle);        (* указатель на объект f:Figure преобразуется в указатель r:Rectangle *)
(* ... *)
(* Переключение вызовов отдельных процедур в соответствии с теми типами процедур,
   которые описаны в общем модуле Figures (без WITH)
 *)
   IF    msg  IS Figures.DrawMsg THEN (* тип записи источника msg = Figures.DrawMsg *)
     Draw(r)
   ELSIF msg IS Figures.ClearMsg THEN (* тип записи источника msg = Figures.ClearMsg *)
     Clear(r)
   ELSIF msg  IS Figures.MarkMsg THEN (* тип записи источника msg = Figures.MarkMsg *)
     Mark(r)
   ELSIF msg  IS Figures.MoveMsg THEN (* тип записи источника msg = Figures.MoveMsg *)
     Move(r, msg(Figures.MoveMsg).dx,
             msg(Figures.MoveMsg).dy) (* преобразование типа записи приёмника msg:Figures.Message
                                                      в тип  записи источника Figures.MoveMsg *)
   ELSE
     (* ничего не делаем \ ignore *)
   END
END Handle;
                                           (* Конструктор объекта r:Rectangle *)
PROCEDURE New* (VAR r:Rectangle);
BEGIN
   NEW(r);                             (* Выделить память объекту r:Rectangle *)
   Figures.Init(r, Rectangles.Handle); (* инициализация скрытого процедурного поля  r.handle()
                                                       реальной процедурой Rectangles.Handle() *)
END New;

END Rectangles.

Несколько критикующих уточнений:

Паскаль, Дельфи и Оберон сегодня от valexey (habrahabr.ru):

Вирт не развивал Оберон-2 (1992-1996) из своего оригинального/классического Оберона (1988-1990). Он по сути лишь консультировал. Основную работу по Оберону-2 провёл Х.Мёссенбёк. По сути, Оберон-2 принадлежит к ветке Object Oberon. Вирт же продолжил развитие Оберона по-своему, что и вылилось в ЯП Oberon-07/rev.2007..20011..2013..2016 (в Обероне-07/2016 нет ничего от Оберона-2, это чистое переосмысление и уточнение оригинального Оберона).

Язык Оберон появился не сам по себе, он появился в рамках проекта написания операционной системы Оберон (1988-1990), и был получен путем упрощения и адаптации Модулы-2 под данную задачу. Более того, без описания ОС Оберон, сообщение о языке Оберон не полно.

ОС Оберон (и соответственно ЯП Оберон) изначально проектировалась под 32-битные процессоры. В дальнейшем мне не известны работы Вирта и его команды по адаптации ЯП Оберон под процессоры с меньшей разрядностью. Сейчас Вирт смотрит в строну микроконтроллеров, и соответственно причёсывает Оберон-07, но здесь опять таки в фаворе 32-битные ARMы (вообще, у Вирта есть даже отдельный форк оберона [англ. fork — вилка, развилка, ответвление] — Oberon-ARM, вот он конкретно под процессоры ARM и был заточен). В сторону поддержки 64-бит существующие языки Оберон-семейства пока не развиваются (исключение есть: AyaCompiler (github.com)).

Приложения на ЯП Оберон подразумевают наличие среды выполнения (рантайма, анг. run time) и сборщика "мусора" (the garbage collector), например, в описаннии Компонентного Паскаля и Оберона-2 это прописано явно, а в описании Оберона и Оберона-07 просто сказано что вот есть NEW, а как освобождать память — не сказано).

В языке многое не определено. Особенно этим грешит Оберон-07. Соответственно могут существовать (и, вообще говоря, существуют) две разных реализации языка, ни в одной букве не противоречащих описанию языка, но при этом не совместимые уже на уровне описания алгоритмов, на уровне базовой семантики. В описании языка также нет ничего про стандартную библиотеку. Так что hello world не написать (т.е. приложение - Привет, мир! Однако, в поставку реального компилятора этот пример входит).

Ну и пачка ссылок на описание языков:

Oberon-2 (1995 год): http://www.math.bas.bg/bantchev/place/oberon/oakwood-guidelines.pdf (www.math.bas.bg)
Component Pascal (2006 год): http://www.oberon.ch/pdf/CP-Lang.pdf (www.oberon.ch)
Вирт часто вносит изменения в публичную версию документа Oberon07.Report.pdf (oberspace.dyndns.org)
Oberon-07 (2016 год): https://www.inf.ethz.ch/personal/wirth/Oberon/Oberon07.Report.pdf (www.inf.ethz.ch)
Язык программирования Оберон-07 (пер.на русский): cкачать (forum.oberoncore.ru)
Revised Oberon-07 Compilers (2011-2016): http://oberon07.com/compilers.xhtml (oberon07.com)

Сложность ERP систем от Noofiz 9 марта 2013 (habrahabr.ru):

NB! Если говорить именно об интерфейсах [в приложениях] и их удобстве, то разработка этих интерфейсов [в приложениях] — это отдельное искусство и большие затраты. Чего греха таить, многие на этом экономят и получают YOUR COMPANY'S APP… (приложение только для своей компании). Заказчики говорят программисту: «Добавь там одну кнопочку...» и так 100 раз в цикле.



Никлаус Вирт в России (www.oberon2005.oberoncore.ru)
https://ru.wikipedia.org/wiki/Глагол_(значения) (ru.wikipedia.org/wiki)
https://ru.wikipedia.org/wiki/Оберон_(язык_программирования) (ru.wikipedia.org/wiki)
https://ru.wikipedia.org/wiki/Языки_программирования_с_ключевыми_словами_не_на_английском (ru.wikipedia.org/wiki)

Что такое компонентно-ориентированное программирование (краткая справка) (www.inr.ac.ru/~info21)
Компонентно-ориентированное программирование это: (dic.academic.ru/dic.nsf/ruwiki/117553)
Идеология компонентно-ориентированного программирования (habrahabr.ru/sandbox/96615)
Компонентно-ориентированное программирование (ru.wikipedia.org/wiki)
Компонентно-ориентированное программирование (ru.wikibooks.org/wiki)
Компонентно-ориентированное программирование (xn--b1aeclack5b4j.xn--e1apq.xn--p1ai/wiki/)
Компонентно-ориентированное программирование (dictionnaire.sensagent.leparisien.fr)
Компонентное программное обеспечение (oberoncore.ru)

BlackBox (www.oberoncore.ru)
Что такое Блэкбокс? (blackboxframework.org)
Что такое Компонентный Паскаль (www.inr.ac.ru/~info21)
Сообщение о языке Компонентный Паскаль (www.inr.ac.ru/~info21)
Язык программирования Оберон-2 (перевод с английского С.Свердлова) (www.uni-vologda.ac.ru)

Product name list with links and remarks (www.modulaware.com)
Component Pascal (www.cfbsoftware.com)
Gardens Point Component Pascal (progopedia.ru)
CPIde (oberspace.dyndns.org)
Оберон-клуб «ВЄДАsoft» (zx.oberon2.ru)
Мысли об Оберонах (www.freepascal.ru)

XDS Oberon-2 (www.excelsior-usa.com)
Oberon Visual Component Library for XDS (www.excelsior-usa.com)
Optimizing Oberon-2 Compiler (sourceforge.net)
Oberon-2 (en.wikipedia.org)
Оберон-2 (язык программирования) (ru.wikipedia.org)

https://github.com/prospero78/Oberon07ru (github.com)
https://github.com/congdm/AyaCompiler /Oberon07 x64/ (github.com)
Oberon-07M (exaprog.com)
Компилятор Oberon-07M (oberoncore.ru)
A resource for the Oberon-07 language (oberon07.com)
Oberon-07M - Нужен ли препроцессор? (oberspace.dyndns.org)
Oberon-07M compiler for Windows (a2os.org.ua)

Дейкстра Э. Дисциплина программирования. М.: Мир, 1978. [основополагающая монография; cкачать, 3.5М].
Сборник избранных статей Эдсгера Дейкстры. cкачать.
Moylan: The case against C [Дело против языка Си] cкачать.
 
 

Вопросы, замечания и предложения высылайте на atimopheyev@yahoo.com

 
Главная     ◄Глагол     Азбука ►   Задачи на Глаголе ►   Примеры приложений ►   Среда разработки ►   Отладка программ ►   Отличия от Оберона ►   Отличия от Паскаля ►   Ассемблер ARM ►   Глагол для ARM ►   ? и Ответы