Quote:
> : >
> : > >> C++ is full of hidden
> : > >> inefficiencies (constructor overhead, implicit copy constructors,
> : > >> etc.)
> : > >
> : > >=========
> : > >Eiffel has creation methods, so I expect this comparison to be less than
> : > >meaningful. That you call them explicitly, without name overloading, is
> : > >hardly relevant to runtime performance.
> : >
> : > Oh yes it is. The point is that implicit copy constructors are one of the
> : > main tools needed in C++ to create abstract data types: its how tell the
> : > language how to make a copy of your object when a bitwise copy won't do. But
> : > then every time you call a function or make an assignment with that type,
> : > the copy constructor gets called. And since C++ lacks garbage collection,
> : > you keep having to make copies so that every module has exactly one copy
> : > to deallocate when its finished with it. In Eiffel you usually pass a
> : > reference around. Much faster.
===========
(My news host didn't carry the article that Mr. Williams is responding to.
I'll add a few remarks here.)
A minor correction about facts is in order before I offer my opinion on GC
and its effects on copying. C++ objects are copied *member-wise* by default,
not bit-wise. The difference in effect is profound.
[ ... in regards to C++ inefficiency in copy constructing ...]
Quote:
> : C++ supports references, either as pointers or as, well,
> : references. In fact, the main difference between C++ and Eiffel in this
> : regard is that Eiffel doesn't allow you to construct a reference to an
> : expanded type, and C++ does.
> From the Eiffel point of view it's nonsensical to do such a thing:
> Value (expanded) types are precisely those things which CANNOT be
> aliased and ":=" has copy-the-value semantics.
> Reference types are those things which CAN be aliased and ":=" has
> copy-the-reference semantics.
==========
This is one of the many little things that add up to major differences in
approaching problems. Eiffel prevents you from passing references that can go
out of scope without explicit action. This is the safest, but also most
pessimistic and restrictive, view of the situation. Ada has what I think is
the most rational, model: it tracks call nesting to determine if passing a
reference might be unsafe. In almost all cases, the nesting count adequately
protects the programmer while allowing reasonable use. C++ places the entire
burden on the programmer, but makes very clear the conditions that would be
"dangerous."
Reference types carry the cost of heap allocation and subsequent sweeping,
marking, and collection. Expanded types cannot be passed by reference, thus
forcing a value-copy, even when a reference can be statically shown to be
safe. C++ allows you to make that determination, and also allows you to "blow
your leg off." Just as with handguns, I find that very few legs are actually
in danger after the first few times.
All this goes back to the snipped discussion regarding costs of C++ copy
constructing, versus Eiffel's pass by reference semantics. I don't know that
we have a clear winner. C++ allows the greatest freedom, permitting the most
efficient use, at the cost of greater burden to the programmer. Some opt for
the safe route of always assuming the worst condition use, and fall back to
Eiffel's inefficiencies. This also has a cost for cognizant programmers: they
often mutter "yeah, but next year's chips will be fast enough."
Quote:
> The C++ notion is muddled because it's still too much like C's notion of
> "this is really gonna get the numerical address in memory of this thing".
=========
I don't know what you mean by this.
Quote:
> : One point to note about garbage collection is the uncertainty it
> : introduces about when objects get deleted and what happens at that
> : time. The more event driven programming I do (both GUI and interrupt
[ ... snipped for brevity ... ]
Quote:
> Why would you use the GC to do that? If you want something done
> deterministically then do what you need to do deterministically.
=========
I don't want to get too heated over this, but determinism about cleanup is
one of the central differences. Bill's example of "guarding" a GUI cursor is
but one example. The whole point about GC is that it is *not* deterministic,
but C++ object scope often is. If we consider implementation issues only,
encapsulating resource allocation this way is very crisp, and almost
always leakproof. Compare this to finalization that would otherwise require a
rescue clause. This causes the abstraction to leak into each feature that
uses the resource. Compare this to an expanded type that is destroyed
reliably *and* specifies a cleanup feature.
Quote:
> If you want something done when there are otherwise no other live
> references to this object then do it through the GC, but this notion is
> inherently not deterministic as it could depend on runtime input.
> : OK, the above example uses a side-effect with a capital
> : S (bold-italic :-) but I see nothing wrong in a paradigm where the
> : environment in which a routine operates is determined by the
> : declarations at the head of the routine.
> So basically you've chosen one particular thing out of the many that an
> object might do, selecting one out of "s.foo" "s.bar" "s.floparound" and
> "s.destruct" to run automatically when the scope of the variable 's'
> goes away.
> Every other time you want to do a routine you write s.routine, except for
> this circumstance.
==========
Quite often, the "thing" selected has some crisp meaning: opening a file,
changing the cursor shape, beginning a database transaction, or allocating
some memory perhaps. Creation grabs the resource; destruction releases it.
The resource is available so long as the object is accessible. Conversely,
the object is inaccessible after the resource has been released. All code
paths cause allocation/release to happen in pairs. Significantly, at least
one language guarantees order of destruction is opposite that of
construction, at statically known points in execution. I'm more surprised
than dismayed that these qualities find disdain rather than acceptance in
some camps.
I get the overall impression that implementation details are beneath notice
for some I have been trading mail with. This is perhaps as it should be for a
specification language. Bertrand promised performance numbers and case
studies on production systems built using Eiffel, to forever dispell the
notion of poor performance. Quite frankly, I'm looking forward to browsing
this information.
Mike.