Question:
It seems like a Class construct would fit in well with the Ada way of
doing things. It seems like a logical evolution from a package, to a
generic package, to a class. Why not just have a class construct?
Answer:
First off, the class construct is used in other popular languages, so
your argument is not without merit. It would be familiar, and its
existence would ease the transition from those other languages.
However, Ada already had some of the features that were added to other
languages by object-oriented extensions. (Not to name any names, but
it's initial is "C".)
For instance, the "class" in C++ is the construct for object-oriented
programming. It's also the construct for encapsulation of related
functions, user definition and extension of types, and templates.
But, except for OO programming, all of these were ALREADY in Ada.
So the designers of Ada 95 were faced with a dilemma: should they
introduce a familiar-looking set of "OO" features that duplicate
existing features of the language, or should they introduce only the
new features needed to make Ada 83 completely OO-capable, when it was
already almost an OOP language to start with?
For fair or foul, they took the second path. I personally think it
was the right technical decision, but it creates a PR difficulty
because people think that the C++ way is the "right" OO way. In fact,
it's ONE approach to OO technology -- neither the best nor the worst,
but certainly the most popular at present.
I feel that the Ada 95 team made the right technical decision because
it kept the language features more orthogonal -- that is, we didn't
wind up with a bunch of different features doing the same thing.
Also, as you stray from the strict C++ model, you find that it's much
easier to define your abstractions clearly in Ada. For instance, you
don't need a "friends" capability, because encapsulation is not
provided by object classes.
There are two areas where I've seen strongly-held objections to the
Ada model:
1. There isn't a "class" construct that encloses the definition of a
class.
First note that in Ada terms, we aren't talking about a class, but
about a type. A C++ "class" defines a template for data storage, and
a set of operations on instances of that template. In Ada, this is a
type. In Ada terminology, a "class" is a family of types. That's why
a "class-wide" parameter can accept a value of a given type OR any of
its descendants: that's an Ada "class." In C++ terms, it can accept a
value of a given class or any subclass of that class.
Anyway, in Ada, if you want to encapsulate the type definition with
its primitive operations, you put a package around it. It just
doesn't use the word "class," but it achieves exactly the same thing
as a C++ class definition.
The advantage to the Ada approach appears when classes are tightly
coupled. The standard example is an OO type and an active iterator
over that type. The iterator needs to see the "innards" of the other
type. In C++ you have to define the iterator class as a "friend" of
the other class. In Ada you can simply encapsulate both types in the
same package, or with the iterator as a child package.
There are other OO design approaches that are harder to implement in
C++ than in Ada, because C++ strongly supports one specific view of
object-oriented technology.
I personally think it would be useful to define some pragma or
comment-flag tags that will encode, in the code, what design approach
is being used. Some things could be checked for you that are not
currently checked, and an ASIS-based tool could look through the
compiled results, find what design approach was intended for a given
chunk of code, and check those specific constraints.
Other people have reacted violently against this idea, for reasons I
did not find clear. It seemed they were arguing that not all code
should conform to the C++ model, and I certainly agree. I do think it
would be useful to encode whether or not a given tagged type was
designed to that model, or to another model, and that the compiler
suite could check it against the constraints of whatever model it was
designed against.
But anyway, my overall point is that encapsulation of a type with its
primitive operations (in C++ terms, a class) is done with the
encapsulation operator in Ada, which is the package. A C++-style
"class" would be a redundant encapsulation operator.
2. You can't use "object.method" notation.
This is another case where the Ada design gives less support to one
specific view of OO technology, because it's supporting more views of
OO technology.
Specifically, the C++ model is that one object "receives a message"
and operates on it, and this is modeled with a function call.
The Ada model is, loosely, that a procedure or function call
identifies an action to occur (or a message, if you prefer),
a set of related information (the non-controlling parameters),
and a set of objects. These objects, all of the same class,
cooperate somehow to accomplish the action (or respond to the
message).
So, if you want to design using a specific "recipient" for each
"message," you can do so. One common approach for this is to use the
first parameter for the "recipient."
You don't get to call out the recipient as part of the syntax, but on
the other hand you don't have to arbitrarily pick one "recipient" if
you aren't using that model of object interaction.
The argument is really whether the language should specifically
support one model of OO technology, to the detriment of other models,
simply because the currently-most-popular OO language uses that model.
I note that people who want "object.method" notation often refer to it
as "class.method" notation. This suggests to me that their objection
is not based in the structure or meaning of the facility, but is about
the code having an unfamiliar "look," because they so often mis-state
the structure and meaning of what they're requesting.
The issue really seems to be that Ada has a different "look and feel"
than C++ or Smalltalk. Adding a "class" encapsulator and
"object.method" notation certainly won't change that!
Trying to write Ada code that conforms to a C++ view of syntax and
semantics is as foolish as trying to write C++ code to look like Ada.
To some extent, if you could just uproot notations from one language
and plop them down in the other, there'd be no reason to have both
languages. I feel that both C++ and Ada have real value. I feel it's
good to have BOTH languages -- our understanding of the deeper issues
is greatly enhanced by having more than one way to express them.
Philosophy final exam: "Describe human thought. Compare and contrast
with any other kind of thought."
|