Re: object system...




"H. S. Lahman" <h.lahman@xxxxxxxxxxx> wrote in message
news:S%79l.4649$Es4.1524@xxxxxxxxxxxxxxxxxxxxxxx
Responding to Grizlyk...

If yes, then you are wrong, because there are even no one OO language
with perfect perfomance.
There is no 3GL that provides perfect performance;
for that you need machine language.

I disagree. General purpose languages of xGL are not desined to
decrease performance of previous (x-1)GL.

It's true that they aren't *designed* to be slower. But the price of
abstraction is performance. Any nontrivial C program with be 30-50% slower
than hand-tuned Assembly. Any C++ program will be 50-200% slower than the
C program.


not always the case.
C is usually fairly comparable to "mundane" assembly...

much of the time, C++ is performance competitive with C (assuming of course
that the C and C++ code operate similarly, for example, the C++ code looks
like C, or the C code uses an object-based approach).

there are many other cases where "abstraction" can be leveraged to the
advantage of the compiler writer, allowing the production of more efficient
code than would have been produced otherwise.

a simple example of this would be compiler provided complexes or vectors,
where a compiler may be able to leverage the capabilities of the processor
(such as specific opcodes for vector handling, ...), and thus generate
faster code than would happen if the coder were to just write a big mass of
scalar code.

or a compiler for a GC'ed framework may notice that an object never survives
past the end of a function call, and may thus use a more efficient means for
allocating the object (such as stack-based memory), whereas a compiler for a
language with manual memory management may fail to take this into account
(so, for example, not only do we have a new/delete pair, but the object also
goes on the main heap, ...).


so, the big issue is not that of how many abstractions are provided, but how
well these abstractions can be leveraged and optimized by the compiler and
runtime.



We use OOPLs for the abstraction and
logical decoupling they provide, not performance.

I disagree. We use OO desing to remove all of the operations, that can
be done automatically, by compler, without any performance lost, not
in order to use abstraction as self-target.

Say, what?!? Abstraction is used to boost developer productivity. Logical
decoupling is used to boost developer productivity during maintenance.
Both are indirectly used to improve reliability. Performance is the price
one pays for the productivity and reliability gains.


again, not always.
they are not mutually opposed, but very often, it is possible to increase
both sets of goals at the same time...


In the early '60s a 1 MLOC application was regarded as gigantic and I
recall an estimate that it would require 1000 engineers working for a
decade to complete such an application. And defect rates in those days
were in the area of 150 defects/KLOC.

We've come a long way since then so that MLOC applications are
small-medium size, they are developed by a group of 8-20 engineers in a
year, and defect rates are down in the 0.5 defects/KLOC range. But you
need a desktop with the computing power of a 1984 mainframe to run exactly
the same spread*** that ran in 1984 on a TRS-80 or an Apple I.

We just don't notice the performance hits paid for greater productivity
because Moore's Law has been working for hardware for nearly half a
century.


of course, this issue is not so much about the languages themselves, or the
level of abstraction, but rather about how the apps are implemented...

the modern spread*** also operates in a GUI environment, and typically
drags along a huge mass of system-related libraries, not all of which are
particularly efficient...


so, yes, usually code bloat does come at the cost of performance, but
abstraction need not be equated to code bloat...



What? Why? Incredibly. Any void concrete implementation is the best of
all others, but unfortunately nearly always unreachable.
Note that an object is defined by its responsibilities. By definition
those responsibilities are obligations to know or do something. The
interface represents access to those obligations. So the object should
never have an interface to access not doing something.

"The interface represents access to those obligations" - I deisagree.
It is possible, we argue about terms only.

OK, let' try this from the Dictionary of Object Technology:

"Interface n. 1. (a) any specification of the boundary of something in
terms of possible interactions or properties that are visible across that
boundary. (b) the visible, outside, user view of something. 2. the
messages to which an object can respond."

That sounds a whole lot like access to me. Also note that in UML an
Interface is a separate model element from a Class. That Interface element
provides an explicit mapping between incoming messages and the operations
or attributes of the Class.


in my case, I consider it more in this latter sense, or more specific, as in
the sense of "interface" as used in languages like Java or C#...


"Programming based on interfaces" is a key of OO desing. Interface is
primary part of an abstraction. An appearence of an abstraction linked
with its interface, not with its implementation. Speaking about an
abstraction we are speaking about its interface.

This is kind of Motherhood & Apple Pie. Encapsulation is a critical notion
in the OO paradigm. So collaborations should be defined in terms of
interfaces. The point is...?


this can also be related to modularity...

so, an interface is an abstraction over a single class, and a module would
be an abstraction over a whole collection of classes (an entire subsystem to
be implemented hidden behind a singular externally-defined API).

this thing frastrates me with many OO devs, which focus all their attention
on micro-abstractions (such as individual classes and interfaces), but fail
to apply similar principles to the larger-scale project (often producing
codebases which are structured as some big elaborate tree with damn near
everything inheriting from everything else).


now, some of us code mostly in C, and have learned to see this issue, if
anything, because if one does not maintain strict modularity and
abstractions, things can quickly start to turn horrible... and, so by the
time one reaches the level of working on 500+ kloc projects, they have long
since learned the need for modular approaches...

this does not mean that this issue goes away in OO languages, only that OO
is "flexible" enough to delay the hard consequences a bit longer, causing
many devs to proceed to form, once again, huge-scale tangled messes of code
(or, for that matter, use the features to conviniently create constructions
which are just distasteful...).

and, then one can see the consequences of this when one proposes... breaking
the app itself into multiple pieces...



So "interface" defines all logical properties of its abstraction (what
to do): responsibilities, access, protocols (sequences of usage) etc.

The dividing between interface ("what to do") and implementation
("how to do") is artificial, not natural of nature, but anyway
"object" never can "define its responsibilities", because "object" is
an instance of interface.

Ah. I see. You are a type maven. B-) So we need a little primer here on
OOA/D.

Types do not even exist in OOA/D (other than knowledge ADTs). OOA/D is
based on class systems rather than type systems. The 3GL type systems are
a compromise with the hardware computational models. As a result they do
not reflect a number of fundamental OO design issues.


and, some of us really value conventional value types as well...


The most important such issue in this thread context is the separation of
message and method. Because 3GLs all employ procedural message passing
there is no distinction; the message is simply the procedure signature.
Since we name procedures by what they do, the message becomes a very
specific imperative to do something (Do This). Unfortunately, that implies
that the sender of the message knows (A) that the receiver exists, (B)
that the receiver does something specific, and (C) that doing it is the
next thing to do in the solution. All of those things trash OO
encapsulation and implementation hiding because it makes it easy to
construct the sender so that it depends on what the receiver does.


yes, this is typically the case, but not always the case...

for example, it is possible to implement a declarative API in terms of
linear calls, where each call serves to inform the callee of the next
element in the structure, rather than telling it what to do about it.

a typical approach then is to make use of a "model" on which these
operations concievably operate, such as an implied tree structure or stack,
and then to build state internally, which may then be operated on once the
final "end" is issued...

in other cases, the API may be asynchronous, for example, by simply adding
something to a queue or a "to-do list"...

granted though, this is a matter of an API's design, and not of the language
itself...


[For example, in a well-formed OO application only knowledge attribute
getters should return a value. If a behavior method returns a value that
creates an instant dependency between the caller and implementation of the
receiver. That is, the caller depends on the *how* the receiver computed
the value because the value must be correct for the caller's own
specification of what it must do. Note that the 3GL type systems can't
enforce that distinction because the type distinction between function vs.
procedure is orthogonal to the semantics of knowledge vs. behavior
responsibilities.]


yes, of course, we can often return handles as well...


Contrast that with OOA/D where message and method are separated. Now a
message is an announcement of something the sender did to change the state
of the solution (I'm Done). All the sender needs to understand is what it
did. So there can be no dependency in its implementation on what will
happen. It is up to the developer to connect the dots of flow of control
so that the message goes to some object that cares about the state change
and can respond appropriately. (In UML that is done at an entirely
different level of abstraction in an Interaction Diagram.) Thus the
separation of message and method is one of the core mechanisms of OO
decoupling.

When message and method are separated, the role of the interface is
different. It exists to provide a mapping between announcement messages
and responses. That's why Interface is a separate model element from the
Class it encapsulates in UML. In OOA/D class systems, the Class defines
the responsibilities that an object has without regard to context; it
describes the intrinsic nature of the object. That nature is mapped to
context through the interface.

But when message and method are coincident as in the 3GL type systems,
there is no distinction between its intrinsic nature and how it is viewed
in the context of the solution. So in 3GL type systems the interface also
defines what the object is.

That's why it is important to understand OOA/D prior to launching into
OOPL coding. If one gets the OOA/D right, then the sender method will not
depend on what the receiver does because it doesn't know anything about
the receiver. Then the fact that the 3GL type systems have trashed OO
decoupling is not a problem.


?...


what is the problem then with seeing the objects in terms of "something that
is"?...
we have objects, we manipulate objects, and we assemble them into larger
structures.

much like, we get a bunch of concrete blocks and rebar and electrical wire
and similar, and can assemble them into a building of a desired form.


we gain abstraction from the concrete block in that we don't have to know
about how it is made or how to keep the sand and agregate together, but none
the less, we have a block, and it is a block.

so, the block and rebar are then assembled, and more concrete is poured to
keep the thing together (we gain abstraction from the concrete by simply
directing its pouring as it emerges from the cement truck, and by not having
to be concerned with where the truck came from or how the concrete was
made...). we also have abstraction by "knowing" that it is a function of the
concrete to turn solid after a set time, and so can begin to schedule the
next stages of the process well before the concrete sets, ...

and elsewhere, a machine extracts and grinds huge masses of limestone, which
is then loaded into trucks, and some of it is taken to the facility which
produces the concrete (this facility directing the trucks to bring agregate,
for example, by making phone calls and giving money).

and, elsewhere again, another facility grinds other components and heats
them in a furnace, producing the cement powder which is again transported to
the concrete facility.

and then, at the demand of the construction worker, the concrete is produced
and loaded into the trucks, and taken back to the construction site.

this does not mean, for example, that the worker depends on the workings of
the entire production process, only that they want concrete, and they get
concrete...

that the facility is buying from agregate producer A or B does not matter
much, nor often that much does the exact type and proportion of agregate
components (limestone, sand, fibers, ...), the worker can just rest assured
that concrete is being produced, and that it adheres to the agreed upon
specifications and costs.


it is not clear why it should need to be the case that this process be
inverted, why the concrete would direct the construction worker rather than
the worker directing the concrete...


likewise for fountain drinks, and many other everyday objects...

we request things from a machine, via its "interface", and then they come
from the machine for us, we need only be responsible for executing the
behaviors that cause this event to take place...


<aside>
Alas, the 3GL type systems are the root of another problem, physical
coupling (i.e., what the compiler or interpreter must know about the
receiver to write correct machine language for the message sender). The
OOPLs do a good job of logical decoupling but they do a terrible job on
physical decoupling. The result is that to make an OOPL program
maintainable one has to do dependency management refactoring *after* the
problem solution is correct. Such refactoring is completely unnecessary
for OOA/D models. Corollary: doing a rigorous OOA/D model will usually
minimize the amount of dependency management refactoring required during
OOP.
</aside>


this kind of thing can be helped by giving the implementation reflective
ability, or by generating the code to bind things together dynamically...


so, we have an object and a task to perform, and the code for performing the
task looks over the object and spews out a chunk of code for performing the
requested action, which is then invoked whenever the action in question
needs to take place.

and, if the object in question is changed? then the code for performing the
task looks over the object and generates a new piece of code, and things
continue as before.


of course, this may imply fairly heavy use of dynamic compilation, and the
need to effectively be able to garbage collect all of the new chunks of code
being so often produced (and, for that matter, the performance impact of
creating new thunks may come into question as well...).



--
Life is the only flaw in an otherwise perfect nonexistence
-- Schopenhauer

H. S. Lahman
H.lahman@xxxxxxxxxxx
software blog: http://pathfinderpeople.blogs.com/hslahman/index.html


.


Quantcast