albobin писал(а):
У Франца с привлечёнными лицами не один этот "папир" вокруг и около 'Lagoon'ы написан, некоторые гуглятся,яндексятся , а вот по самой 'Lagoon'е не очень.
Если повезёт наткнутся на текст "The Programming Language Lagoona - A Fresh Look at Object-Orientation", то там идеи изложены на Оберон-базе.
Я сам не эксперт, не берусь перевирать. Но как-то примерно так:
Вводятся два "взгляда" на объекты, первый - место в иерархии типов, второй - принадлежность к неким Интерфейсам (И.),определяющее поведение объекта.
Месседжи (Мес.) вводятся на уровне модуля как самостоятельная сущность, вроде абстрактной операции. Они при определении не привязанны ни к каким типам.
(И.) группируют (Мес.). (И.) - это тоже типы. Вводятся Объекты (О.) на базе Рекордов и с принадлежностью к (И.) Методы (Мет.) прибиты к (О.) и реализуют реакцию на (Мес.) Если (О.) принадлежит к некому (И.), то должны быть все (Мет.), реализующие реакции на все (Мес.) данного (И.) . Это статически контролируется компилятором. В принципе любой (Мес.) можно послать любому (О.). Если у (О.) нет соответствующего (Мет.), то (Мес.) игнорируется, но есть еще механизм перенаправления (Мес.) другим (О.) и дефолтный (Мет.) - реакция на всё непонятное.
Переменные интерфейсного типа могут "принимать" (О.) любых типов (из разных мест иерархии типов) , но принадлежащих данному интерфейсу. Это - одна из "фишек" подхода.
Вообщем, лучше читать оригинал.
Если кому интересна проблематика. Откопал пару альтернативных публикаций, в принципе, раскрывающих суть Lagoona:
[1] Component-Oriented Programming in Object-Oriented Languages[2] Supporting software composition at the programming language levelНиже выдержка из [1], демонстрация к цитате выше.
Имеются (согласно примерам в публикации) некоторые фреймворки, независимые (от разных поставщиков), требующие реализации компонентов согласно интерфейсам (Java-like):
Код:
Fig. 1. An interface for the abstract data type Stack
package framework1;
interface Stack {
// Add object to stack as topmost object.
// REQUIRE o != null; ENSURE this.top () == o;
void push (Object o);
// If stack not empty, remove topmost object.
// REQUIRE !this.empty();
void pop ();
// If stack not empty, return topmost object.
// REQUIRE !this.empty(); ENSURE result != null;
Object top ();
// No object on stack?
boolean empty ();
}
Fig. 3. An interface compatible with Fig. 1
package framework2;
interface Stack {
// Add object to stack as topmost object.
// REQUIRE o != null; ENSURE this.top () == o;
void push (Object o);
// If stack not empty, remove topmost object.
// REQUIRE this.size > 0;
void pop ();
// If stack not empty, return topmost object.
// REQUIRE this.size > 0; ENSURE result != null;
Object top ();
// Number of objects on stack?
// ENSURE result >= 0;
int size ();
}
Fig. 5. An interface syntactically incompatible with Fig. 1 and Fig. 3
package framework3;
interface Stack {
// Add object to stack as topmost object.
// REQUIRE o != null;
void push (Object o);
// If stack not empty, remove and return topmost object.
// REQUIRE !this.empty(); ENSURE result != null;
Object pop ();
// No object on stack?
boolean empty ();
}
Fig. 6. An interface semantically incompatible with Fig. 3
package framework4;
interface Stack {
// If stack not full, add object to stack as topmost object.
// REQUIRE (o != null) && (!this.full()); ENSURE this.top () == o;
void push (Object o);
// If stack not empty, remove topmost object.
// REQUIRE !this.empty();
void pop ();
// If stack not empty, return topmost object.
// REQUIRE !this.empty(); ENSURE result != null;
Object top ();
// No object on stack?
boolean empty ();
// Stack full.
boolean full ();
// Remaining size of stack?
// ENSURE result >= 0;
int size ();
}
Так задаются интерфейсы и их реализация в Lagoona (в стартовой цитате -- краткое описание принципов, операция "->" -- "отправка" сообщения):
Код:
Fig. 9. A Lagoona interface for the abstract data type Stack.
MODULE Framework1;
MESSAGE
(* Add object to stack as topmost object. *)
(* REQUIRE o # NIL; ENSURE Top() = o; *)
Push (IN o: ANY);
(* If stack not empty, remove topmost object. *)
(* REQUIRE ~Empty(); *)
Pop ();
(* If stack not empty, return topmost object. *)
(* REQUIRE ~Empty(); ENSURE result # NIL; *)
Top (): ANY;
(* No object on stack? *)
Empty (): BOOLEAN;
TYPE
Stack = {Push, Pop, Top, Empty};
END Framework1.
Fig. 10. Our Lagoona implementation conforming to Fig. 9.
MODULE Component;
IMPORT
F1 := Framework1, V := Com.Lagoona.Util.Vectors;
TYPE
Stack = RECORD rep: V.Vector; END;
METHOD (OUT self: Stack) NEW ();
BEGIN NEW (self.rep);
END NEW;
METHOD (INOUT self: Stack) F1.Push (IN o: ANY);
BEGIN V.Add (0, o) -> self.rep;
END F1.Push;
METHOD (INOUT self: Stack) F1.Pop ();
BEGIN V.Remove (0) -> self.rep;
END F1.Pop;
METHOD (IN self: Stack) F1.Top (): ANY;
RETURN V.ElementAt (0) -> self.rep;
END F1.Top;
METHOD (IN self: Stack) F1.Empty (): BOOLEAN;
RETURN V.Size (0) -> self.rep = 0;
END F1.Empty;
END Component.
Так можно задать реализацию сразу четырёх интерфейсов (в цитате выше):
Код:
Fig. 11. Our Lagoona implementation conforming to all four interfaces.
MODULE Component;
IMPORT
F1 := Framework1, F2 := Framework2, F3 := Framework3,
F4 := Framework4, V := Lagoona.Util.Vector;
TYPE
Stack = RECORD rep: V.Vector; END;
METHOD (OUT self: Stack) NEW ();
BEGIN NEW (self.rep);
END NEW;
METHOD (INOUT self: Stack) F1.Push, F2.Push, F3.Push, F4.Push (IN o: ANY);
BEGIN V.Add (0, o) -> self.rep;
END F1.Push, F2.Push, F3.Push, F4.Push;
METHOD (INOUT self: Stack) F1.Pop, F2.Pop, F4.Pop ();
BEGIN V.Remove (0) -> self.rep;
END F1.Pop, F2.Pop, F4.Pop;
METHOD (INOUT self: Stack) F3.Pop (): ANY;
RETURN V.Remove (0) -> self.rep;
END F3.Pop;
METHOD (IN self: Stack) F1.Top, F2.Top, F4.Top (): ANY;
RETURN V.ElementAt (0) -> self.rep;
END F1.Top, F2.Top, F4.Top;
METHOD (IN self: Stack) F1.Empty, F3.Empty, F4.Empty (): BOOLEAN;
RETURN F2.Size () -> self = 0;
END F1.Empty, F3.Empty, F4.Empty;
METHOD (IN self: Stack) F4.Full (): BOOLEAN;
RETURN FALSE;
END F4.Full;
METHOD (IN self: Stack) F2.Size (): INTEGER;
RETURN V.Size () -> self.rep;
END F2.Size;
METHOD (IN self: Stack) F4.Size (): INTEGER;
RETURN MAX(INTEGER);
END F4.Size;
END Component.
В работе [2] несколько шире изложена проблематика наследования в ООП и "классических" интерфейсов, представлена реализация уже на Net. Выдержка для примера:
Код:
Fig. 7. Naive publishers and subscribers in Java.
package com.lagoona.pubsub ;
public interface Publisher {
void attach (Subscriber me );
void detach (Subscriber me );
Object get ();
void set (Object data );
}
public interface Subscriber {
void update (Publisher from );
}
Fig. 8. Smarter publishers and subscribers in Lagoona: only get can be sent within update.
module com.lagoona.pubsub {
interface Publisher {attach , detach , get , set }
message void attach (Subscriber me );
message void detach (Subscriber me );
message castable Any get ();
message void set (castable Any data );
interface Subscriber {update }
message void update (interface {get } from );
}
Ключевое: в рамках Lagoona для Subscriber есть возможность указать ограничение для интерфейса -- метод update принимает в качестве входа только лишь объект с методом get (что предотвращает проблемы -- нет возможности вызывать прочие методы publisher-а во время реакции на событие в subscriber-е).
Языковые конструкции расширены, напр., директивой castable -- разрешение на приведение типов. И пр.
В общем, впечатление, что в Lagoona предполагалась какая-то форма модульности в стиле ML и его производных, но с ограниченными возможностями (прежде всего, имеется ввиду понимание в ML структур и сигнатур, их соответствие друг другу, в т.ч. "прозрачное" и "тёмное" (ограничения для типов или представление их в другом виде)).