An example of the declaration of an active object in sC++
is given in slide ex-active.
The sC++ language is implemented as an extension to the GNU C++ compiler.
The sC++ runtime environment offers the possibility
to validate a program by executing random walks,
which is a powerful way to check the various synchronization conditions.
The model of active objects supported by sC++
has also been realized as a Java library, see
As argumented in draft version 0.1 (15/7/2001)data abstraction -- state accessible by operations
strong typing -- compile time checking
Object-based versus object-oriented
How would you characterize Ada83? See Classes versus types
Another confusion that frequently arises
is due to the ill-defined relationship between
the notion of a class and the notion of a type.
The notion of types is already familiar
from procedural programming languages such as
Pascal and (in an ill-famed way) from C.
The type of variables and functions may be profitably
used to check for (syntactical) errors.
Strong static type checking may prevent errors
ranging from simple typos to using undefined
(or wrongly defined) functions.
The notion of a class originally has a more
operational meaning.
Operationally, a class is a template for object creation.
In other words, a class is a description of the collection
of its instances, that is the objects that are
created using the class description as a recipe.
Related to this notion of a class, inheritance was
originally defined as a means to share (parts of)
a description.
Sharing by (inheritance) derivation is, pragmatically,
very convenient.
It provides a more controlled way of code sharing
than, for example, the use of macros and file inclusion
(as were popular in the C community).
Since Towards an orthogonal approach -- type extensions
According to Orthogonal approach
Objects
are in essence modular computing agents.
They correspond to the need for encapsulation in design,
that is the construction of modular units to
which a principle of locality applies (due to
combining data and operations).
Object-oriented languages may, however, differ in
the degree to which they support encapsulation.
For example, in a distributed environment a
high degree of encapsulation must be offered,
prohibiting attempts to alter global variables
(from within an object) or local instance
variables (from without).
Moreover, the runtime object support system must
allow for what may best be called remote method invocation.
As far as parallel activity is concerned, only a few languages provide
constructs to define concurrently active objects.
See section Active for a more detailed discussion.
Whether objects support reactiveness,
that is sufficient flexibility to respond safely
to a message, depends largely upon (program) design.
Types
may be understood as a mechanism for expression classification.
From this perspective, Smalltalk may be regarded
as having a dynamic typing system:
dynamic, in the sense that the inability to evaluate an expression
will lead to a runtime error.
The existence of types obviates the need to have classes,
since a type may be considered as a more abstract description of the
behavior of an object.
Furthermore, subclasses (as may be derived through inheritance)
are more safely defined as subtypes in a polymorphic
type system. See section flavors.
At the opposite side of the type dimension we find the statically typed languages,
which allow us to determine the type of
the designation of a variable at compile-time.
In that case, the runtime support system need not carry any type information,
except a dispatch table to locate virtual functions.
Delegation
(in its most generic sense)
is a mechanism for resource sharing.
As has been shown in Abstraction
(although to some extent related to types)
is a mechanism that may be independently applied to provide
an interface specification for an object.
For example, in the presence of active objects
(that may execute in parallel)
we may need to be able to restrict dynamically the interface of an object as specified by its type
in order to maintain the object in a consistent state.
Also for purely sequential objects we may impose a particular protocol of interaction
(as may, for example, be expressed by a contract) to be able to
guarantee correct behavior.
Another important aspect of abstraction is protection.
Object-oriented languages may provide (at least) two kinds
of protection.
First, a language may have facilities to
protect the object from illegal access by a client (from without).
This is effected by annotations such as private and protected.
And secondly, a language may have facilities to protect the object
(as it were from within) from illegal access through delegation
(that is by instances of derived object classes).
Most languages support the first kind of protection.
Only few languages, among which are C++ and Java, support the second kind too.
The independence of abstraction and typing may further
be argued by pointing out that languages
supporting strong typing need not
enforce the use of abstract data types having a well-defined
behavior.
Multi-paradigm languages -- logic
Object-oriented programming has evolved as a new and
strong paradigm of programming.
Has it?
Of the languages mentioned, only Smalltalk
has what may be considered a radically new language design
(and to some extent also the language Self, that we will
discuss in the next section).
Most of the other languages, including Eiffel, C++
(and for that matter also CLOS and Oberon),
may be considered as object-oriented extensions of already
existing languages or, to put it more broadly, language
paradigms.
Most popular are, evidently, object-oriented extensions
based on procedural language paradigms,
closely followed by the (Lisp-based) extensions of the
functional language paradigm.
Less well-known are extensions based on the logic programming
paradigm, of which DLP is my favorite example.
In Open systems
Dimensions of modularity
Object-oriented logic programming
Logic programming is often characterized as relational
programming, since it allows the exhaustive
exploration of a search space defined by logical relations
(for instance, by backtracking as in Prolog).
The advantage of logic programming, from a modeling point of view,
is that it allows us to specify in a logical manner
(that is by logical clauses) the relations between
the entities of a particular domain.
A number of efforts to combine logic programming with
object-oriented features have been undertaken,
among which is the development of the language Vulcan.
Vulcan is based on the Concurrent Prolog language
and relies on a way of implementing objects as
perpetual processes.
Without going into detail, the idea (originally proposed in
Active objects -- synchronous Java/C++
When it comes to combining objects
(the building blocks in an object-oriented approach)
with processes (the building blocks in
parallel computing),
there are three approaches conceivable.
See slide 6-o-conc.
Object-based concurrency
Processes
The first, most straightforward approach,
is to simply add processes
as a primitive data type, allowing the
creation of independent threads of processing.
An example is Distributed Smalltalk (see Bennett, 1987).
Another example is Java, which provides support for
threads, synchronized methods and statements like wait
and notify to protect re-entrant concurrent methods.
The disadvantage of this approach,
however,
is that the programmer has full responsibility
for the most difficult part of parallel programming,
namely the synchronization between processes and the
avoidance of common errors
such as simultaneously assigning a value to a shared
variable.
Despite the fact that the literature, see Active objects
A second, and in my view preferable, approach
is to introduce explicitly a notion of active objects.
Within this approach, parallelism is introduced by having
multiple, simultaneously active objects.
An example of a language supporting active objects
is POOL, described in Asynchronous communication
Deadlock may come about by synchronous (indirect)
self-invocation.
An immediate solution to this problem is provided
by languages supporting asynchronous communication,
which provide message buffers allowing the caller
to proceed without waiting for an answer.
Asynchronous message passing, however,
radically deviates from the (synchronous) message passing
supported by the traditional (passive) object
model.
This has the following consequences.
First, for the programmer, it becomes impossible
to know when a message will be dealt with
and, consequently, when to expect an answer.
Secondly, for the language implementor,
allocating resources for storing
incoming messages and deciding when to deal
with messages waiting in a message buffer
becomes a responsibility for which it is hard to
find a general, yet efficient, solution.
Active objects with asynchronous message passing
constitute the so-called actor model,
which has
influenced several
language
designs. See Synchronous C++/Java
[]
readme
course
preface
1
2
3
4
5
6
7
8
9
10
11
12
appendix
lectures
resources
eliens@cs.vu.nl