In article <335D64A7.167E@nospam.acm.org> Thant Tessman <firstname.lastname@example.org>
> And I recommend folks learn *any* language that supports higher-order
> functions, automatic memory management, and incremental compilation
> to see how truly wretched C++ is, regardless of whatever claims
> Stroustrup makes for it.
I learned Standard ML, which has all three of these properties,
several years ago, and I can say with confidence that from where
I sit, C++ is not wretched by comparison -- just different.
Each language has its strengths and weaknesses.
For example, I can write programs that manipulate trees and tree-like
data structures much more easily in ML than I can in C++, as long as
I stick to the operations that ML supports. But it can be useful sometimes
to do things that ML doesn't support well, and those things are much
harder to implement in a language that has trees virtually built in
than in a language where trees are built on top of a lower-level
Here is a somewhat simplistic example. The following ML code defines a
binary-tree data structure where each node contains a value and is
either a leaf or has two subtrees:
datatype 'a Tree = LEAF of 'a | TREE of 'a Tree * 'a Tree
Gorgeous! It's hard to imagine how such structures could be easier
to define. Now let me define a function that takes a tree and a
pair of values x and y and yields a new tree in which all nodes containing
x now contain y:
fun replace(t, x, y) =
case t of
LEAF a => LEAF (if a=x then y else a)
| TREE (left, right) =>
TREE(replace(left, x, y), replace(right, x, y))
Again, it's really nice to be able to write code like this.
But now suppose we want to be able to identify a specific subtree of a tree.
If I had gone to the trouble of creating a tree abstraction in C++, I could
identify a particular subtree by the address of its root. But there's no
corresponding facility in ML. Trees are values, and although one can compare
them for equality, there is no notion of object identity.
One way to solve that problem is to use ML references for the tree nodes.
But then the trees really do become objects, and treating them as values
becomes much more difficult. Moreover, I might not have thought I would
need to identify particular subtrees, and changing an existing data structure
to use references requires rewriting all of the code that uses it.
I have discussed this particular problem with people who know ML far better
than I do, and they agree that it is a problem. The best solution anyone has
offered is to define another abstraction that represents a path from the root
of a tree to a particular node, and traverse the tree in terms of such abstract
paths. This is not particularly hard to do in the example above, because there
are only two kinds of nodes involved. But if we were dealing with parse trees
in a programming environment, there might be dozens of kinds of nodes, and
the solution would become much more difficult.
Of course the real answer is to structure one's ML programs so as to avoid
such knotty problems. But that's exactly my point! Although ML offers
abstractions that make some programs extremely easy to write, it does so at
a cost. A professional attitude toward solving problems involves looking
at the tools available, picking the most useful one for the context --
the WHOLE context -- and then using it.
Incidentally, this whole discussion talks only about language. In deciding
what programming tools to use, there is more than that to consider. After
all, if all you care about is how easy the language is for you to use, why not
just invent your own language? You won't have a compiler for it unless you
write one, but if ease of programming is all you care about, that doesn't
matter. Of course, this facetious remark is intended to illustrate that
having a compiler that works well in your context matters too. But even that
is not all that matters. There is also the question of what tools your
use, and what tools the people might be using who will be maintaining your
code, and what machines you might be called on to support in the future.
C++ built on C precisely so that it would appeal to the existing C community.
As a result, support tools, a body of knowledge, and a community came along
more readily than they would have if the language had been designed totally
from scratch. And that knowledge and community, and those tools, are among
the main reasons why C++ is now in widespread commercial use and so many
of the designed-from-scratch languages are not.