Stefan said:
»There were two versions of it, one in Lisp and one in
C++. The display subsystem of the Lisp version was faster.
There were various reasons, but an important one was GC:
the C++ code copied a lot of buffers because they got
passed around in fairly complex ways, so it could be quite
difficult to know when one could be deallocated. To avoid
that problem, the C++ programmers just copied. The Lisp
was GCed, so the Lisp programmers never had to worry about
it; they just passed the buffers around, which reduced
both memory use and CPU cycles spent copying.«
Yes, it's completely "fair" to compare a C++ program which doesn't
understand the concept of a smart pointer to lisp, where "smart
pointers" (in the sense that memory is garbage-collected) are inherent.
Yes: It requires more work to make that work in C++ with smart
pointers than the same thing in lisp (although making a copy-on-write
version of std::vector is not all that hard). However, that doesn't mean
that the C++ version cannot be as efficient as the lisp version. It only
means the C++ programmers were incompetent.
»A lot of us thought in the 1990s that the big battle would
be between procedural and object oriented programming, and
we thought that object oriented programming would provide
a big boost in programmer productivity. I thought that,
too. Some people still think that. It turns out we were
wrong. Object oriented programming is handy dandy, but
it's not really the productivity booster that was
promised. The real significant productivity advance we've
had in programming has been from languages which manage
memory for you automatically.«
I still wouldn't trade modules (the most crucial part of OOP) for GC,
if I had to make an excluding choice.
»[A]llocation in modern JVMs is far faster than the best
performing malloc implementations. The common code path
for new Object() in HotSpot 1.4.2 and later is
approximately 10 machine instructions (data provided by
Sun; see Resources), whereas the best performing malloc
implementations in C require on average between 60 and 100
instructions per call (Detlefs, et. al.; see Resources).
I like how this misses one of the main reasons why memory allocation
can be slow: Cache behavior.
From experience I would estimate that the number of instructions
executed when allocating/deallocating amounts to maybe 10-20% of the
total speed, and the remaining 80-90% depends on how cache-friendly the
allocation system is. Cache misses are enormously expensive.
Good GC engines do indeed have the advantage that they can defragment
memory and make allocations more cache-friendly. This is harder (but not
impossible) to do in C/C++.
»Perhaps the most important realisation I had while developing
this critique is that high level languages are more important
to programming than object-orientation. That is, languages
which have the attribute that they remove the burden of
bookkeeping from the programmer to enhance maintainability and
flexibility are more significant than languages which just
add object-oriented features. While C++ adds object-orientation
to C, it fails in the more important attribute of being high
level. This greatly diminishes any benefits of the
object-oriented paradigm.«
On the other hand many "high-level languages" offer abstractions at
the expense of memory usage efficiency. There are "high-level languages"
where it's prohibitively difficult to create very memory-efficient
programs (which handle enormous amounts of data) while still maintaining
a fair amount of abstraction and maintainability.
This seems to have been the trend during the past 10-20 years:
Completely disregard memory usage efficiency in favor of higher level
abstractions. After all, everybody has a supercomputer on their desk and
everything they do with it is play tic-tac-toe. You don't need memory
usage efficiency, right?
C++ might not be all fancy-pancy with all the latest fads in
programming, but at least it offers the tools to write very
memory-efficient programs which are still very well designed, with a
high degree of modularity, abstraction and maintainability. That cannot
be said about all programming languages.