|
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 разрешены несколько охраняемых ветвей (ELSIF … DO). Тем самым обеспечена полная явная поддержка цикла Дейкстры. Ранее цикл Дейкстры моделировался при помощи цикла 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.
Шаблон-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качать.
Языки программирования (lurkmore.to). умора обо всех ЯП. Обновлён в 2018 году.
|
|