If you read the popular computer magazines these days it seems
that everyone is talking and writing about object oriented
programming (OOP). Quite frankly I fail to see what all the fuss
is about (much of the time I can't understand what is being
written about either). Here is a description of OOP from "The
Software Challenge" in the Time Life series, Understanding
Computers reprinted in 1990:
Object oriented programming, a relatively recent
addition to the ranks of programming techniques, offers
an attractive alternative [to traditional sequential
programming]. It accomodates the fact that people tend
to perceive the world in terms of objects, which may
interact with one another but are nonetheless
identifiable as independent entities. Thus, instead of
a continuous stream of instructions, object oriented
programs organize data and procedures into small chunks
called objects, each of which represents a discrete
element or aspect of the situation being simulated.
These program chunks can be assembled, disassembled,
and rearranged by the programmer like building blocks,
and each can be tested or adjusted separately, making a
large and complex program far easier to write and debug
than it would be if it were written in the conventional
way. Objects can also be lifted from one program and
used in another with little or no modification.
Since the early 1980's dozens of object oriented
programming techniques have been developed.
Is this not a perfect description of what GOOD FORTRAN
programmers have been doing for decades? I myself am a FORTRAN
user and have been since 1973. It seems to me that this
paragraph describes perfectly my programming style as it has been
for the last 13 years at least. Interestingly, FORTRAN is NEVER
referred to in writings on OOP. Am I missing the point here; is
there more to this OOP stuff than appears on the surface?
Ross Taylor
Department of Chemical Engineering
Clarkson University
Potsdam, NY 13699 (yes, we have our own zip code)
tay...@sun.soe.clarkson.edu
I have tried writing a molecular dynamics program in OO design. It
was dificult (for me). the atoms in the molecule all interact with
each other, so partitioning the physical system into discrete objects
with minimal interactions was tough. I refused to consider atoms as
objects for efficiency reasons. The way OO software "oughta" work is
that each object cannot access data local to another object directly.
You have to provide function calls to allow other objects to see or
modify data local to one object. I think global data is non-existent
in religious OO. anyway, if atoms were objects, anything that needed
atomic coordinates would have to use function calls to get the
coordinates for each atom. putting function calls in computationally
intense kernal loops kills vectorization, or even scalar efficiency on
scalar computers. I was able to use OO design to partition my program
into the molecule object, the force interaction object, and the
biograf file liason object. as far as implementation was concerned,
the programming was decidely non-OO (in the religious sense i
understand it; my understanding of OO is very shaky). instead of
sending distances via function calls, i "sent" it via include file
with common block. oh evil of evils...
the difference between modular fortran programming and OO is not
having global data in OO. the argument is if you change the global
data, you wind up changing code distributed all throughout your code.
in OO, changing data in one object only effects that single object.
other code is isolated because it only uses function calls, which are
not allowed to change. what i don't understand is what is the
difference between changing global data in modular programming and
having to change function calls in OO. it seems like a semantic
difference to me. we could pretend fortran arrays are function calls
and say we have always done OO... I have GOT to be missing something!
--
Scott| ARPA: lam...@crd.ge.com
Lamson| UUCP: uunet!crd.ge.com!lamson
(518)387-5795| UUCP: uunet!sierra.crd.ge.com!lamson
General Electric Corporate Research and Development
I think the point is that OOPS languages do alot of this for you.
For example, you can define attributes for an object that then
are inherited by other objects, something that would have to be
done by hand in Fortran. I am new to OOPS, so I am not the one
to discuss this in detail, but an analogy might be to recursion.
You can do it in Fortran (in effect) by building stacks, but it
is done automatically for you by Pascal, C, and other languages
(and will be done by Fortran Extended as well).
John K. Prentice
Amparo Corporation
Albuquerque, NM
You are missing something as far as understanding what OO is about (and
I'm no expert either), but you aren't missing something critical: OO, used
in a straightforward fashion, can be anywhere from a wee bit faster to
hugely slower than traditional techniques. You've identified an excellent
case of either overusing OO techniques or overextending OO design techniques
into the implementation of the program to the point of significantly
affecting performance. This issue applies just as well to the techniques
we consider "traditional": think of what would happen if you coded all your
additions, subtractions, multiplications, array references, and so on,
as procedure calls!
As far as answering the question "what is OO", I have an answer that might
help:
OO is, in a practical sense, a more general way of organizing procedures
than the named-procedure method we currently use.
While OO includes, depending on who you ask, many concepts, the key ones
I know of are:
1) data abstraction
2) data hiding
3) inheritance
4) polymorphism
#s 1 and 4 are available in limited ways in Fortran and other traditional
languages, and #2 is available though usually in an even more limited way
(especially as regards performance). #3 is usually the kicker that gets
people so excited about OO, especially when you throw in run-time
polymorphism, which most people seem to include in definitions of OO.
The advantages these concepts give you is that they provide yet another
excellent set of design tools -- ways to think about your problem -- and,
further, OO systems make it easy to convert the resulting design to a
running program.
However, there are few reasons not to use OO techniques "in brain" and "on
paper", as I often do, and still limit oneself to traditional techniques
involving structured programming, procedure calls, etc, to gain the
advantages of proven system technology and performance.
One reason to go directly from OO design to OO implementation is that you've
given the computer more high-level information on your problem, which can
mean easier maintenance and higher possible performance. However, since
OO technology is new, the maintenance is only a small win (compared to the
promise OO holds for the future) and performance is often a big loss.
I'd like to build an OO compiling and optimizing system that actually
makes otherwise equivalent OO and non-OO programs show the OO version as
the better performer, because as a compiler designer I think I can always
do better the more my compiler is told about what is really going on.
However, OO invites the creation of lots of conceptual procedures, or
"methods" (sequences of code just like ordinary procedures that deal with
a "message" sent to a given object), and the easiest way to build an OO
system is to map those conceptual procedures into real ones. The result
is lots more procedures than you otherwise would have. So you either need
a global optimizer or you take the C++ approach where you allow the
procedure to be declared "inline" so it gets expanded right in line (just
like how most compilers handle statement functions in Fortran). This is
how I'd handle your problem with atoms, if I felt abstracting down to that
level was indeed worthwhile.
As far as global data goes, the OO approach to that is that you can think
of a global "object" that responds to "messages", which you seem to have
grasped. How "global" is the object? Fortran provides very coarse
granularity here, but OO systems (and C and Pascal...) typically provide
much finer granularity, including something roughly equivalent to COMMON,
so you'll be fine handling things that way.
Now, the methods for those messages are essentially procedure calls, but
if they are designated "inline", the result should be no slower than
putting the variables for the object (and its class) into COMMON and
directly accessing them there.
The advantage of the OO approach here is that, with it, all users of the
global object are coded in such a way that it is easy to change the
internal representation of that object -- by changing its definition instead
of all its uses -- or to do things like insert debugging statements, tests,
and so on.
So your concern about function calls accessing data isn't quite true any
more than a concern that structured programming requires +, -, and * to
be thought of as procedures -- essentially they are overloaded (or
polymorphic) inline procedures, to combine the theoretical with the
practical I suppose, and similarly in OO you don't really create function
calls per se, but methods that implement messages. Whether the implementation
of a message, that is a method, consists of a procedure call or an inline
call, is supposed to be unimportant to the user of that object, and
an issue only for the implementor of that object.
One advantage I can think of for using OO is that you could define a
particular class called "collection of atoms" that knew how to perform
calculations on groups of atoms. Users of this class would send it
simple messages, but their implementations might expand into inline DO
loops over all the atoms and such. Operations like adding and removing
atoms could later be extended to leave information around making subsequent
("typical") operations more optimal, without having to change the
client code.
Ultimately, OO is primarily a boost towards organizing one's programs, kind
of the next step beyond having simple procedure names and dummy arguments.
It isn't a "new programming paradigm" in the sense that logic programming,
functional programming, imperative programming (Fortran, C, ...), and,
say, neural nets are different from each other; in fact, I'd say that just
as all of these areas can (and, I think, do) benefit from simple naming
of collections of knowledge (we call them procedures here in imperative-
land), they probably all could benefit from OO concepts to improve
organization and maintenance.
With C++, one can show that OO is really just a "layer" on top of C, as
indicated by the fact that many C++ implementations really just convert
C++ code into somewhat goofy-looking but hardly unreadable C (i.e. it's
a fairly direct translation -- they aren't creating a simulator or something
like that!).
However, with Fortran, one can easily imagine useful things an OO approach
to the language would be able to add without being implementable using
the same "layered" approach on top of existing Fortran implementations
(and I'm not including "inline" in this, since it is just an optimization
"hint" in C++).
For example:
SUBROUTINE VECTOR_ADD(A,B,C,N)
INTEGER N
TYPE(NUMBER) A(N),B(N),C(N)
INTEGER I
DO I=1,N
C(I) = A(I) + B(I)
END DO
END
While the subroutine itself isn't a great example of using OO techniques,
it might be a typical example of a method for an array type, and it
shows run-time polymorphism for the arrays A, B, and C. Naturally, all
callers of this subroutine would have to access an interface body for
the subroutine (Fortran 90 terminology for "know that it expects its first
three arguments to be TYPE(NUMBER)).
With this definition, one could call VECTOR_ADD with arrays of
INTEGER, REAL, COMPLEX, DOUBLE PRECISION, or other types (or combinations
of types) for which assignment (=) and addition (+) are defined as
valid operations).
A straightforward implementation would be slow, because for each execution
of the + operator, the compiler would have generated a procedure call to
the appropriate method for A(I)'s type (here I'm assuming for the sake
of sanity that all elements of an array are of the same type, as does
regular Fortran and most other ordinary compiled languages) with the value
in B(I) as an argument, and another call to do the assignment of the
result returned by the first procedure call to C(I) by calling C's
method for assignment.
But a modestly smart compiler doing only intra-procedure optimization (the
kind most of us are used to) could figure out that it is faster to test
the types of A, B, and C at the top and handle certain common cases (all
INTEGER, all REAL, all DOUBLE PRECISION, all COMPLEX, ...) using separately
compiled (and hence much faster) loops.
Next, by declaring the procedure INLINE, each call to the subroutine would
be compiled as if the subroutine was included inline. Even though the code
itself would look the same, the compiler might be able to determine that,
for a given call, the types of A, B, and C were known, and create a fast
inline loop or at least a call to a particular implementation of the
VECTOR_ADD method tuned for that particular combination of types.
The availability of a global optimizer would theoretically remove the need
for specifying INLINE, doing such analysis fairly automatically.
Now, what's the advantage of VECTOR_ADD as an OO-style method or subroutine
versus the current approach? Well, in this case, the main advantage is
that you now have one subroutine that knows how to do a straightforward
case of vector add (I didn't deal with strides and such, for reasons of
simplicity) independent of the data types involved -- as long as they
support addition (i.e. character types aren't automagically dealt with --
unless you create an addition operator for the character type!). The
alternative? Having separate versions of VECTOR_ADD for every combination
of types of arrays you need -- which could be extensive, especially in an
interactive application like a statistical package.
In fact, generally speaking, programs "want" to be OO-organized more and
more as they permit more and more freedom for the users with which they
interact. It's not a hard-and-fast rule, and by no means the only rule
for when OO is useful. But the more freedom you want to allow an interactive
user in dealing with data (objects) in your application, the more you want
to be able to separate actions (methods) from actual data formats, and it
is a lot easier to create a few modules like VECTOR_ADD above than
bezillions of copies for all the combinations that a user MIGHT want.
(Note that you might really want to have a more general vector operator
that sends a given message, in the VECTOR_ADD case, +, to all the elements
of a vector, and given this, you don't really have VECTOR_ADD and its
siblings for other operators, but one VECTOR_APPLY method that takes a
message as its arguments...though I don't know offhand which OO systems
support such a thing.)
In summary, OO really doesn't give you a new way of coding. Instead, it
gives you yet another, fairly well thought-out and researched, way to
organize your code, either conceptually or in source form, and it uses
a model that often closely parallels real-life examples. Mapping its
approach directly into source code can improve maintainability and
readability, reduce the chances of typing errors in some cases, but can
have performance drawbacks mainly because the state of the art is not
as advanced as for the older organize-around-procedure-names approach
either for the compiler systems or for the programmers doing the
implementation. But there seems to be no inherent reason that a "pure"
design using OO techniques (correctly) cannot be as fast as a similarly
pure design using older procedure-naming techniques, or ultimately
faster (since the system is told at least as much, and sometimes more,
about the program). In the meantime, you can certainly learn to use OO
techniques to get a handle on OO and on thorny problems, and even to
prototype and test them, but still use traditional techniques to create
production versions, just as you can prototype systems at the procedure-
name level and then rewrite them in assembly to get them to run acceptably
fast.
--
James Craig Burley, Software Craftsperson bur...@ai.mit.edu
IMHO, most such "advances" are basically attempts to formalize
the rather nebulous concept of "good programming". Maybe there is
more underneath, but I've never seen it either.
I mainly, however, wanted to respond to the lack of Fortran in OOP
discussions. There is an article:
@ARTICLE{wampler-90-object-oriented,
AUTHOR = {K. Dean Wampler},
TITLE = {The Object--oriented Programming Paradigm {(OOPP)} and
{FORTRAN} Programs},
JOURNAL = {Computers in Physics},
YEAR = {1990},
VOLUME = {4},
NUMBER = {4},
PAGES = {385--394},
MONTH = {July/August}
}
which specifically discusses OOP in the context of Fortran. The
problem with OOFortran is that the F77 standard doesn't really have
the constructs one wants to do it "properly". F90 will remedy most of
these deficiencies. Until then, Wampler shows that it is possible
to simulate OOP ideas using F77 (and also gives the F90 code).
--
David Bernholdt bern...@qtp.ufl.edu
Quantum Theory Project bern...@ufpine.bitnet
University of Florida
Gainesville, FL 32611 904/392 6365
> SUBROUTINE VECTOR_ADD(A,B,C,N)
> INTEGER N
> TYPE(NUMBER) A(N),B(N),C(N)
> INTEGER I
> DO I=1,N
> C(I) = A(I) + B(I)
> END DO
> END
Is this OO? I thought OO versus PO (procedure oriented or algorithm
oriented) would have all code for integer objects grouped together
for vector add, vector multiply, etc. The PO alternative wouldbe to
group the procedure for all different data types (objects) together.
We saw this distinction between stardent AVS and GE/CRD VISAGE, two
generic scientific visualization tools,where VISAGE is OO. AVS groups
by algorithm for all possible field types (isosurface generator for
uniform fields, rectilinear fields, irregular fields, and unstructured
meshes), whereas in OO VISAGE, all algorithms that apply to
uniform fields are grouped together. So if you change the
implementation of a particular data structure, you need to change all
AVS modules that work on it; in VISAGE, you only change code within
the objects for that data type. On the other hand, if a new algorithm
for isosurface generation comes along, AVS would change a single
module, whereas VISAGE would have to change the isosurface code in
each object. I am not sure which is fundamentally better. aren't
algorithms more likely to be changed than data structures?
I understand inheritance is a big advantage to OO systems, but i can't
see why inheritance couldn't be applied in PO approaches. there just
are no PO implementations that provide it.
Finally I would like to recommend an article from BYTE, April 1990,
"New Objects for Old Structures", by Jeff Duntemann and Chris Marinacci
for those of you who are interested in mixing object oriented and
traditional thoughts. Also I would like to recommend BYTEs, August 1981,
August 1986 and March 1989.
B.T.W. I do not usually read this newsgroup, but was directed here from
comp.object. If anybody has something to say that he/she thinks I should
read, it is best to mail it to me.
--
Nasser ABBASI abb...@smaug.enet.dec.com
--or-- ...!decwrl!smaug.enet.dec.com!abbasi
--or-- abbasi%smau...@decwrl.dec.com
>From: bur...@pogo.ai.mit.edu (Craig Burley)
>For example:
> SUBROUTINE VECTOR_ADD(A,B,C,N)
> INTEGER N
> TYPE(NUMBER) A(N),B(N),C(N)
> INTEGER I
> DO I=1,N
> C(I) = A(I) + B(I)
> END DO
> END
Is this OO? I thought OO versus PO (procedure oriented or algorithm
oriented) would have all code for integer objects grouped together
for vector add, vector multiply, etc.
You raise a good point, but I had to submit with a shudder because I didn't
want to get into all the complexity of the situation.
Actually, I'd say that INTEGER, REAL, COMPLEX, ... all inherit from type
NUMBER, and that ADD is a (virtual, hence non-existent) method provided
by NUMBER. Then, ARRAY (of some sort) also would be a type (class) and
would support vector operations of an elemental sort, including
VECTOR_ADD -- or, better yet, a generic operator that applies a given
operator to all the elements of one or more same-shaped arrays, in which
case VECTOR_ADD would simply be a "macro" reference to that operator.
The point of the above example is to show how one could write subroutines
to do things without having to worry so much about their types. The
vector add example was a simple one to grab, easy to type and understand,
and yet include performance implications worth discussing.
For an example of where Fortran really falls down is writing a subroutine
like this:
SUBROUTINE WRITENOTE(UNIT,TEXT)
INTEGER UNIT
CHARACTER*(*) TEXT
WRITE(UNIT=UNIT,FMT=*) 'Note: ' // TEXT
END
Now callers can say CALL WRITENOTE(5,'Delete junk files'), for example,
but how can they say the equivalent of WRITE(UNIT=*,...) by calling
WRITENOTE? Fortran provides no way of getting some canonical unit
number for "*".
This is a trivial example, but if Fortran were re-engineered around its
useful semantics and an OO paradigm, then, like C++ vs. C, it's I/O
model would be much more useful and flexible. (For example, instead of
passing around unit numbers as integers, such a language would pass
around something we might call STREAMs, which could, on a given system,
be just an integer, of course; and the equivalent of * could still be
provided, but in a more flexible way.) I tried to illustrate this using a
tip-of-the-iceberg example.
There has been some work done at RAE in Farnboro', UK by G. Butler and
M. Corbin on 'O-O Simulation in Fortran-77'. I have a working paper (ref:
MM 388/89) which discusses a subroutine library to support O-O techniques
(and includes source for this library). The paper may have or be appearing
in SCS Simulation Journal but I don't have any details.
Their full address is: Royal Aerospace Establishment
Farnborough
GU14 6TD
UK.
R. Bentley
+------------------------------------+----------------------------+
| uucp : ...!mcvax!ukc!dcl-cs!dik | Department of Computing |
| arpa : dik%lancs...@ucl.cs | University of Lancaster |
| janet: d...@uk.ac.lancs.comp | Bailrigg, Lancaster |
| tel : (44) 524 65201 x3119 | LA1 4YR, UK. |
+------------------------------------+----------------------------+