Oberon space
General Category => Общий раздел => Тема начата: Geniepro от Август 28, 2013, 06:44:33 am
-
Даёшь дженерики! Даёшь инициализацию массивов!! Даёшь динамические массивы!!! )))
С динамическими массивами все понятно, а про дженерики много разговоров, но пока я не видел описание синтаксиса и семантики дженериков для оберона. Возможно, следует обсудить синтаксис и семантику дженериков (я в этом вопросе слабо разбираюсь).
Ну как вариант -- как-то так:
Lightweight Parametric Polymorphism for Oberon (http://research.microsoft.com/en-us/um/people/cszypers/pub/jmlc97.pdf) (Paul Roe and Clemens Szyperski)
By combining Oberon's inclusion polymorphism (subtyping) with parametric polymorphism, the map procedure can be abstracted to work for entire families of collections, not only lists.
TYPE Ptr(A) = POINTER TO A;
TYPE Proc(A) = PROCEDURE (x: Ptr(A));
TYPE Collection(A) = Ptr(CollectionDesc(A));
CollectionDesc(A) = RECORD
elem: Ptr(A)
END;
List(A) = Ptr(ListDesc(A));
ListDesc(A) = RECORD (CollectionDesc(A))
next: List(A)
END;
Tree(A) = Ptr(TreeDesc(A));
TreeDesc(A) = RECORD (CollectionDesc(A))
left, right: Tree(A)
END;
PROCEDURE <A> (c: Collection(A)) Map (p: Proc(A));
BEGIN p(c.elem)
END Map;
PROCEDURE <A> (l: List(A)) Map (p: Proc(A));
BEGIN
l.Map^(p); (* "super call" to overridden procedure *)
IF l.next # NIL THEN l.next.Map(p) END
END Map;
PROCEDURE <A> (t: Tree(A)) Map (p: Proc(A));
BEGIN
IF t.left # NIL THEN t.left.Map(p) END;
l.Map^(p);
IF t.right # NIL THEN t.right.Map(p) END
END Map;
For example, it is now possible to abstractly map Rotate over a collection of points Collection(PointDesc), regardless of whether the collection is actually a list, a tree, or any other structure derived from the base type Collection(A).
-
Без вникания в тему сказать тяжело, но мне кажется, что мой вариант тоже будет работать
TYPE
ArrList(T) = RECORD a: ARRAY OF T; size: INTEGER END;
PROCEDURE (l: ArrList) Add(i: T);
BEGIN
IF l.size >= LEN(l) THEN l.a := Expand(l.a) END;
l.a[size] := i;
size := size + 1
END Add;
PROCEDURE (l: ArrList) Get(i: INTEGER): T;
BEGIN
RETURN l.a[i]
END Get;
PROCEDURE Do;
VAR l: List(MyType);
item: MyType;
BEGIN
Init(item);
InitList(l);
l.Add(item);
END;
Впридачу, он ещё и локаничнее.
-
Без вникания в тему сказать тяжело, но мне кажется, что мой вариант тоже будет работать
PROCEDURE (l: ArrList) Add(i: T);
В придачу, он ещё и лаконичнее.
А откуда здесь тип T взялся?
-
А откуда здесь тип T взялся?
Из объявления типа:ArrList(T) = RECORD a: ARRAY OF T; size: INTEGER END;
-
А откуда здесь тип T взялся?
Из объявления типа:ArrList(T) = RECORD a: ARRAY OF T; size: INTEGER END;
Ну и как у Вас тут связаны тип и процедуры?
TYPE
ArrList(T) = RECORD a: ARRAY OF T; size: INTEGER END;
PROCEDURE (l: ArrList) Add(i: T);
BEGIN
IF l.size >= LEN(l) THEN l.a := Expand(l.a) END;
l.a[size] := i;
size := size + 1
END Add;
PROCEDURE (l: ArrList) Get(i: INTEGER): T;
BEGIN
RETURN l.a[i]
END Get;
Т в объявлениях процедур выскакивает как чёртик из табакерки, нарушая принцип наименьшего удивления...
-
TYPE
ArrList(T) = RECORD a: ARRAY OF T; size: INTEGER END;
PROCEDURE (l: ArrList) Add(i: T);
BEGIN
IF l.size >= LEN(l) THEN l.a := Expand(l.a) END;
l.a[size] := i;
size := size + 1
END Add;
-
А если программист сделает так:
TYPE
ArrList(T) = RECORD a: ARRAY OF T; size: INTEGER END;
... тонна кода ...
PROCEDURE (l: ArrList) Add(i: M);
BEGIN
IF l.size >= LEN(l) THEN l.a := Expand(l.a) END;
l.a[size] := i;
size := size + 1
END Add;
Скажем, что он сам себе злой буратина?
-
Кроме того, процедуры же могут содержать несколько полиморфных параметров:
PROCEDURE <A, B, C> Foo(a: A; b: B): C;
...
Как тут быть с Вашим подходом?
-
Вообще, если уж улучшать систему типов оберона, добавляя в неё дженерики, то надо бы избавиться и от таких рудиментов как
TYPE PList = POINTER TO List;
List = RECORD
elem: SomeType;
next: PList
END;
Во всех современных языках делается так:
TYPE List = RECORD
elem: SomeType;
next: POINTER TO List
END;
Кроме того, предложенный Шиперским вариант обозначения дженериков различается у типов и процедур, это неконсистентный дизайн, имхо.
<A> пошло от всяких сишарпов и с++, на треугольные скобки накладывается лишний функционал, а, например, фигурные скобки вообще не используются.
И, кстати, в обероне-07 вроде нет процедур, привязанных к записям, как в обероне-2?
Короче, пример из первого сообщения может выглядеть как-то так:
TYPE Proc{A} = PROCEDURE (x: A);
TYPE Collection{A} = RECORD
elem: A
END;
List{A} = RECORD (Collection{A})
next: POINTER TO List{A}
END;
Tree{A} = RECORD (Collection{A})
left, right: POINTER TO Tree{A}
END;
PROCEDURE Map{A} (c: Collection{A}; p: Proc{A});
BEGIN p(c.elem)
END Map;
PROCEDURE Map{A} (l: List{A}; p: Proc{A});
BEGIN
Map{A}(l, p); (* "super call" to overridden procedure *)
IF l.next # NIL THEN Map{A}(l.next, p) END
END Map;
PROCEDURE Map{A} (t: Tree{A}; p: Proc{A});
BEGIN
IF t.left # NIL THEN Map{A}(t.left, p) END;
Map{A}(l, p);
IF t.right # NIL THEN Map{A}(t.right, p) END
END Map;
Правда, тут получилась перегрузка имён процедур, а как известно всем образованным программистам, лучший способ пергрузочного полиформизма -- это классы типов ))
ЗЫ. С другой стороны, фигурные скобки можно было бы отвести под инициализаторы массивов и записей. Нагружать этой функцией круглые или прямоугольные тоже не очень.
ЗЗы. С третьей стороны, круглые скобки можно считать инициализатором процедуры -- список параметров, так что и для роли инициализатора массива или записи тоже вроде годится...
PPPS. А если ещё и ключевые слова в нижнем регистре, да ещё и light-syntax (значимые отступы)... Короче, это уже нельзя будет назвать Обероном. В лучшем случае какой-нить Титанией )))
-
PROCEDURE (l: ArrList) Add(i: M);
...
Скажем, что он сам себе злой буратина?
Ну да. А что странного? Ошибка же. Или как?
-
Кроме того, процедуры же могут содержать несколько полиморфных параметров:
...
Как тут быть с Вашим подходом?
Так же, как и у Шиперского.
-
PROCEDURE (l: ArrList) Add(i: M);
...
Скажем, что он сам себе злой буратина?
Ну да. А что странного? Ошибка же. Или как?
Место, где указано правильное написание этого параметра, слишком далеко от места его употребления. Чревато ошибками, что нежелательно...
-
Вообще, если уж улучшать систему типов оберона, добавляя в неё дженерики, то надо бы избавиться и от ... рудиментов
Я, предлагая свой вариант, пытался также пояснить, что это лишь первый набросок. Возможно, есть вариант что-то улучшить. Однако, я считаю свой вариант более логичным, чем у Шиперского.
-
... фигурные скобки вообще не используются.
Чёртовы множества, никогда ими не пользовался и совсем забыл, что в оберонах они задаются в этих фигурных скобках...
-
Вообще, если уж улучшать систему типов оберона, добавляя в неё дженерики, то надо бы избавиться и от ... рудиментов
Я, предлагая свой вариант, пытался также пояснить, что это лишь первый набросок. Возможно, есть вариант что-то улучшить. Однако, я считаю свой вариант более логичным, чем у Шиперского.
В обероне-07 нет методов, вместо них процедурные переменные с явной инициализацией (в какой-нибудь фабрике).
То есть такой код для Оберона-07 невалиден:
PROCEDURE (t: Tree) Insert (node: Tree); ...
Вообще, это же похоже на сишарпные методам расширений (extension method), а это опять же полпути к классам типов...
-
В обероне-07 нет методов, вместо них процедурные переменные с явной инициализацией (в какой-нибудь фабрике).
В обероне 07 и обобщённых типов нет. Я лишь сделал пример Шиперского более простым.
-
Я лишь сделал пример Шиперского более простым.
Не уверен, что Ваш вариант стал проще. Менее понятным (с непривычки, возможно), более способствующим багам -- да. Разве ж это проще?