|
Method combination is the support in an object-oriented
language for the implicit construction of behavior of a method based
on the behavior of more than one implementation of that method. In
CLOS, this is achieved using :before and
:after methods, and call-next-method . In
BETA, method combination is achieved using the INNER
imperative in virtual methods. The :before and
:after based method combination would be a particular
way of using the existing constructs in BETA.
In gbeta, there is support for a more large scale method combination,
because a top-level type combination operation might give
rise to any number of consequent, implicit type combination
operations, depending on the declarations in the participating
patterns.
Example 2
As an example, it is possible to construct a stack
data-structure which supports being used in a concurrent context by
means of the combination of two aspects, in this case the
concurrency aspect and the implementation aspect. Other aspects could
be brought into play as well, in combinations as you wish.
(* FILE aex2.gb *)
-- betaenv:descriptor --
(# (* This example shows how the constraint based type analysis
* makes it possible to combine several patterns by doing
* just one top-level inheritance operation, in the
* declaration of 'myStack'. This is an important reason
* why the constraint based inheritance mechanism supports
* a deeper separation of concerns.
*
* The basic idea is that we separate the concurrency
* control aspect and the sequential implementation
* aspect in the expression of a stack datatype which
* must be usable in a multithreaded context.
*
* The implementation is largely absent, but there
* should be enough of it to make it understandable
* what is going on by single-stepping the program
*)
monitor:
(# mutex: @semaphore;
init: (# do mutex.V #);
entry: (# do mutex.P; INNER; mutex.V #)
#);
list: (* just a dummy impl. with a type parameter *)
(# element:< object #);
stack:
(# element:< object;
init:< object;
push:< (# e: ^element enter e[] do INNER #);
pop:< (# e: ^element do INNER exit e[] #)
#);
threadsafeStack: stack
(# mon: @monitor;
init::< (# do mon.init; INNER #);
push::< mon.entry;
pop::< mon.entry
#);
listStack: stack
(# storage: @list(# element::this(listStack).element #);
push::< (# do (* .. *) INNER #);
pop::< (# do (* .. *) INNER #)
#);
myStack: @ threadSafeStack & listStack
do
myStack.init;
&object[]->myStack.push
#) |
The implementation of the push method consists of two
different contributions, namely the contribution from
threadSafeStack and the contribution
listStack . The contributions are merges in accordance
with the general type combination rules.
The next topic is the interplay of mutual recursion and
specialization (inheritance).
| |