Что лучше: связанные процедуры или процедурный тип?

Это непростой вопрос. Наверное, в зависимости от того, что вы пишете. Насколько там простые или сложные объекты.


              * * *

Подход к ООП в оригинальном Обероне и Обероне-07:

(Кстати, Оберон-07 в своём сообщении о языке не считается таковым, он просто называется «Оберон», а затем написано, что это ревизия от такого-то числа).

Процедурные переменные могут отлично работать во многих случаях. Они проще с точки зрения упрощения языка, то есть для них не надо знать каких-то дополнительных конструкций языка, весь ООП пишется теми же средствами, как и без использования ООП. В сравнении с другими способами ООП на Обероне здесь есть некоторая гибкость. (Можно поэкспериментировать, придумать что-то своё.) Есть различные подходы: процедурные переменные в каждой записи, отдельная запись с методами для всего типа, шины сообщений (особенно ценная вещь, даже в КП и Обероне-2).

Процедурные переменные в каждой записи

MODULE Bitmaps; TYPE Bitmap* = POINTER TO BitmapDesc; BitmapDesc* = RECORD Line*: PROCEDURE(b: Bitmap; x1, y1, x2, y2: INTEGER); END; PROCEDURE Line(b: Bitmap; x1, y1, x2, y2: INTEGER); BEGIN END Line; PROCEDURE InitBitmap*(VAR b: BitmapDesc); (* вариант: (b: Bitmap) ... *) BEGIN b.Line := Line END InitBitmap; PROCEDURE NewBitmap*(): Bitmap; VAR b: Bitmap; BEGIN NEW(b); InitBitmap(b^); (* ...тогда здесь (b) *) RETURN b END NewBitmap; END Bitmaps. (* Как пользоваться (в другом модуле): *) PROCEDURE Test; VAR b: Bitmaps.Bitmap; BEGIN b := Bitmaps.NewBitmap(); b.Line(b, 5, 5, 90, 90) END Test;

Отдельная запись с методами для всего типа

Шины сообщений


              * * *

Подход к ООП в Обероне-2 и Компонентном Паскале:

Связанные с типом процедуры (type-bound procedures) проще с точки зрения непосредственно их использования, так как они поддерживаются языком. Язык при этом становится чуточку сложнее, так как в нём появляются процедуры с двумя наборами скобок в заголовке:

PROCEDURE (b: Bitmap) Line(x, y: INTEGER);

Здесь приходится решать ещё один вопрос: выполнить ли данную процедуру обработки записи в виде обычной процедурой или выполнить её в виде процедуры, связанной с типом. Кстати, при этом процедуры, связанные с типом, который представляет собой нерасширяемую запись, ничем в машинном коде не отличаются от обычных процедур, а значит представляют собой просто альтернативную запись того же, что можно было сделать и обычной процедурой (такое иногда называют «синтаксическим сахаром»). Последнее относится только к КП.

Я проводил некоторые практические исследования этого вопроса. К однозначным выводам пока не пришёл. Я писал библиотеку графического интерфейса пользователя с нуля в каждом из этих четырёх стилей ООП, чтобы посмотреть, может ли нестандартное программирование ООП превратиться в удобную привычку и чтобы сравнить получившийся код на предмет его понятности. Из очевидного: Подход КП и Оберон-2 намного лаконичнее.


              * * *

Ещё есть такой язык как Объективный Оберон (Objective Oberon, предтеча Оберона-2). В нём связанные с типом процедуры указаны внутри объявления типа, а затем ниже повторяются ещё раз. Как в Объективном Паскале или в Си++ (в одном из вариантов написания методов в Си++).


              * * *

И, наконец, есть язык Активный Оберон (Active Oberon), в котором наряду со словом RECORD есть слово OBJECT, а связанные с типом процедуры указываются целиком внутри конструкции OBJECT, как в одном из вариантов написания на Си++.

28 декабря 2020 г.
г. Рига, ЛССР