Article Discussion
The C++ Style Sweet Spot
Summary: Bjarne Stroustrup talks with Bill Venners about the perils of staying too low level and venturing too object-oriented in C++ programming style.
66 posts on 5 pages.      
The ability to add new comments in this discussion is temporarily disabled.
Most recent reply: February 22, 2004 10:11 AM by
Merriodoc
Posts: 14 / Nickname: brandybuck / Registered: March 24, 2003 6:00 AM
Re: The C++ Style Sweet Spot
October 17, 2003 5:49 AM      
> "When in Rome, do as the Romans do."
>
> If you are lucky - like I am - you happen to find the true
> C++ way of multiparadigm design a natural - as good as or
> even better than "pure OO" - way to think about design and
> programming.

This is one of the reasons I like Python as well as C++. You can do either procedural or OO as needed, and they both look logical in the language.

Most of the performance talk here has been about numeric types. I think where you really get the performance boost in C++ is in the ability to combine an OO design with the low-level memory access allowed in C. Recently somebody I work with was troubleshooting a performance problem with putting a large report together in XML. One of the issues is that the string manipulation was just too darn slow with all of the packaged classes (string and XML) in C++ and in various other languages (It was prototyped in VB and that required a lot of patience in large cases), so we put together a class specifically for concatenating and manipulating very large strings. When you got to really large strings (500MB+), the file I/O was taking longer than the creation of the string. Previously large reports were taking a horribly long time. The class cut a 20 minute operation (our main test cases were ~20 minutes and didn't remotely approach 500MB reports) down to well under 1 on average.

I can't imagine a 1/2 GB string in Java, Python, <insert your favorite dynamic interpreted garbage collected language here>, etc. As for numerics, as many people have already pointed out, that is easy to get around in many languages. In Python you can extend the language with a module written in C/C++ for performance critical pieces. Java is pretty good in most cases with numerics. In the Microsoft world you can create a COM object that can be called for any critical tasks. And so on.

I always get a little nervous when I hear about "the one true way" when it comes to programming. Some tools are better than others for some tasks and it helps to have some understanding of as many as reasonably possible. Having everything be an object may (I question this still from time to time, I don't buy it) be more elegant, but objects always carry baggage and sometimes that baggage needs to be dumped.

I'm sure many people will disagree with this statement, but I feel that when elegance gets in the way of solving a real problem, elegance must go. At the end of the day your customer (client, manager, internal users of your app in a corporation, etc.) doesn't give a poop about whether your application has a great class structure, makes clever uses of collections/dictionaries/hash tables, uses Exceptions instead of return codes for error handling, is purely object oriented or not, follows some self imposed 'rule of X' where you don't ever have more than X methods in a class, etc. They care that the application gets their job done in a reasonable fashion. All of the above mentioned things more often than not help you get to your goal, but all they are is tools. Something to help you get where you're going. They are not an end in and of themselves.
Bjarne
Posts: 48 / Nickname: bjarne / Registered: October 17, 2003 3:32 AM
Re: The C++ Style Sweet Spot
October 17, 2003 8:52 AM      
> BTW, there's also a new signal/slot library added to
> Boost. And not mentioning Boost when talking about C++
> libraries which offer what the standard library doesn't > is a severe shortcoming, IMHO.

I usually refer to BOOST in my talks and if I remember rightly I mention it later in this interview - you haven't seen half of it yet.

Anyway, there is much more to C++, its use, its libraries, and its tools than can be mentioned in an interview. For more see: my home pages: http://www.research.att.com/~bs
Matt
Posts: 62 / Nickname: matt / Registered: February 6, 2002 7:27 AM
Re: The C++ Style Sweet Spot
October 17, 2003 11:40 AM      
> can't imagine a 1/2 GB string in Java, Python...

I just tried it in the Python interpreter and it works fine. Deleting it frees up the memory pretty quick, too.

Nevertheless, you'd still want to use C/C++ for such large strings, because in languages where strings are immutable, it is pretty easy to end up with lots of intermediate copies if you aren't careful and since modifying a string means copying it, the C/C++ alternative will be much faster.

Once again, it gets down to using the best tool for the task. Right now C/C++ is best for 500MB strings, but in a decade languages like Python and Ruby will be (and then we'll be talking about using C/C++ for 500GB (or perhaps 500TB?!?) strings).

As for the shootout links, the neatest thing about them is you can look at code for the same algorithms in a lot of different languages. That's a good way to find languages that strike your fancy and merit more investigation.

Of course, some of those implementations are not very optimal. Or maybe it is that implementation across languages is uniform, which can be an advantage, disadvantage or neutral, depending on the language/platform. For example the Fibonacci example seems to only test which language is best at recursion, but it certainly is not the best approach for solving the problem in many languages (see http://www.artima.com/forums/flat.jsp?forum=32&thread=4996&message=16761&redirect=true&hilite=true&q=Fibonacci). What's more interesting to me is that some problems seem to work better in some languages, because the sub-optimal implementation, but when implemented more optimally for each language, different winners will emerge. For example, with a better Fibonacci implementation, you quickly get to numbers that you cannot handle in C/C++ without creating or finding a BigInt class (with the better implementation than recursive one, you quickly get out of the unsigned long range) and you find that Python works with them much more efficiently than Java.
Merriodoc
Posts: 14 / Nickname: brandybuck / Registered: March 24, 2003 6:00 AM
Re: The C++ Style Sweet Spot
October 17, 2003 0:25 PM      
> Of course, some of those implementations are not very
> optimal. Or maybe it is that implementation across
> languages is uniform, which can be an advantage,
> disadvantage or neutral, depending on the
> language/platform. For example the Fibonacci example
> seems to only test which language is best at recursion,
> but it certainly is not the best approach for solving the
> problem in many languages (see
> http://www.artima.com/forums/flat.jsp?forum=32&thread=4996&
> essage=16761&redirect=true&hilite=true&q=Fibonacci).
> What's more interesting to me is that some problems seem
> m to work better in some languages, because the
> sub-optimal implementation, but when implemented more
> optimally for each language, different winners will
> emerge. For example, with a better Fibonacci
> implementation, you quickly get to numbers that you cannot
> handle in C/C++ without creating or finding a BigInt class
> (with the better implementation than recursive one, you
> quickly get out of the unsigned long range) and you
> find that Python works with them much more efficiently
> than Java.

I remember the whole fibonacci debate. And it was at the simplicity and efficiency of this example in that discussion


fibs = [0,1,1]
def smartFib(n):
for i in range(len(fibs),n+1):
fibs.append( fibs[-1] + fibs[-2] )
return fibs[n]


that I went wow. And this is where I got the notion that in learning any language (still new to Python and still enjoying the learning process :-) that it is very helpful to know how things in it really work. I've always thought blanket statements in matters of development were bad and this, more than any other single example and discussion I've seen to date, really made it hit home. There are general principles that are good to follow and that can be applied across a wide swath of problems, but the need to dig deep into a problem and get the best solution to your particular instance sometimes requires bending the rules. Or figuring out how to best apply those principles using the tools available, which may in some ways contradict the conventional wisdom.

I think everybody learns the fibonacci recursion example and thinks that how it should always be written because that's how you first learn it. Never mind that two classes later you learn about how recursion can be a performance nightmare and you can use a stack to easily remove tail recursion. Everybody goes back to the CS101 recursive version when talking about fibonacci numbers, even though everbody learned in CS309 that it probably isn't the best, most efficient way to implement it.

I found something similar with creating primes in Python. I ran across this link http://www.networkcomputing.com/unixworld/tutorial/005/005.html and liked the prime number example, so I figured I would try it on 1,000,000. Well, it finishes, but it's not very fast (or even half-fast), so I tinkered with it for a few minutes and came up with

def MyPrime(limit):
limit = limit + 1
PrimeDict = {2:'Y'}

#initialize prime dictionary
for x in range(3,limit):
PrimeDict[x] = 'Y'

RetList = []
#tag all non-prime numbers
for x in range(2,limit):
if PrimeDict[x] <> 'N':
RetList.append(x)
for y in range(2*x,limit,x):
PrimeDict[y] = 'N'

RetList.sort()
return RetList


which does goes up to 1,000,000 and returns all 78498 primes between 2 and 1,000,000 in about 4 seconds. I felt happy :-) I'm no phd like the author of the article, but I like tinkering with Primes too. Mine just happens to be a lot more memory intensive where his is more CPU intensive. At least that's what my performance monitor tells me.

Anyway, I agree with you that it gets down to using the best tool for the job. That's why I like having a lot of tools in my toolbelt. It's even better if you really know how to use the tool.

I inadvertently typed

>>> x = primes.MyPrime(10001000)

in the python interpreter and it came back after a few minutes.
>>> x[-1]
10000993
I never knew 10,000,993 was a prime number (can't say I ever really cared...) and that there were 664640 prime numbers

>>> len(x)
664640

up to 10,001,000. And I love the negative slicing in python sequences. That language feature ROCKS! It's such a silly little thing when you think about it, but I love it.

I think you have to look at the shootout links with a grain of salt, mostly because of the reason sited in your link to the fibonacci debate. Optimal solutions tend to look different from one language to the next, and in some cases the language is a good fit for the problem and in others you look at the solution and go huh? I think if you really want to get a feel for a language, you need to look at optimal solutions for problems in them. That'll tell you what the language can really do. This is why I never was a big perl fan. There are probably as many optimal solutions for a problem as there are good perl developers.

This is also why .NET perplexes me a bit. Why bother developing a CLR and bolting different languages onto it? You have to in some cases shoehorn your language into the runtime and in the process destroy some of the things that are good and right about it. I don't know if the Python on .NET initiative has really gone anywhere, but I remember reading about some of the initial attempts and the concessions you have to make to get Python running right in the CLR causes some serious problems with it. Last I knew the best bet was to follow active perl and have a bridge so you can access the runtime from Python and vice versa. Ah, I digress...

My condolences to any fellow Red Sox fans out there. Go Marlins!
Isaac
Posts: 51 / Nickname: igouy / Registered: July 10, 2003 7:42 AM
Re: The C++ Style Sweet Spot
October 17, 2003 3:17 PM      
> For example the Fibonacci example
> seems to only test which language is best at recursion

That was his intention - to test how well languages handle recursion. Other micro-benchmarks were intended to test array access... etc More reasonable to complain that they don't test what they were intended to - for example hash.

> some implementations are not very optimal
some implementations have simple mistakes ;-)
some implementations are too optimised - they are no longer idiomatic

Yes, the coolest thing is that you can see code from 40 languages. Hopefully the number of language implementations will continue to grow - Fortran? compiled Lisp/Scheme? Intel C, faster MLs, ...
Matt
Posts: 62 / Nickname: matt / Registered: February 6, 2002 7:27 AM
Re: The C++ Style Sweet Spot
October 17, 2003 3:39 PM      
Batch files, WinBatch, COBAL, C-Shell, Assembly...
Matt
Posts: 62 / Nickname: matt / Registered: February 6, 2002 7:27 AM
Re: The C++ Style Sweet Spot
October 18, 2003 7:09 AM      
Here's the Fibonacci as a batch file!

@echo off
setlocal
if [%1]==[] goto syntax
set x=1
set y=1
set fib=1
set count=1
if /i %1 leq 1 goto done

:loop
set /a count=%count%+1
set /a fib=%x%+%y%
set x=%y%
set y=%fib%
if /i %count% geq %1 goto done
goto loop

:syntax
echo Specify a number (up to 47 works well) to get the
echo corresponding Fibonacci value.
goto end
:done
echo Fibonacci of %1 is %fib%
goto end
:end
endlocal
Bjarne
Posts: 48 / Nickname: bjarne / Registered: October 17, 2003 3:32 AM
Re: The C++ Style Sweet Spot
October 18, 2003 8:27 AM      
>
> > some implementations are not very optimal
> some implementations have simple mistakes ;-)
> some implementations are too optimised - they are no
> longer idiomatic
>
> Yes, the coolest thing is that you can see code from 40
> languages. Hopefully the number of language
> implementations will continue to grow - Fortran? compiled
> Lisp/Scheme? Intel C, faster MLs, ...

The C++ examples seem to be C style. To contrast, here is a Fibonachi class. The constructor makes a sequence of the first n Fibonachi numbers stating with n1 and n2:

template<class T> class Fib
{
vector<T> seq;
public:
Fib(int n, const T& n1 = T(2), const T& n2 = T(2))
{
seq.push_back(n1);
seq.push_back(n2);
for (int i = 1; i<n; ++i) seq.push_back(seq[ i]+seq[i-1]);
}
const T& operator[](int i) { return seq; }
int size() { return seq.size(); }
};

Given that you can make Fibonachi sequences of any type supporting addition. For example:

Fib<int> si(10);
Fib<string> ss(10,"a","b");

This is of course just a "silly example" but it does illustrate my point that there is good C++ that is neither C-style nor based on class hierarchies.

- Bjarne Stroustrup; http://www.research.att.com/~bs
Isaac
Posts: 51 / Nickname: igouy / Registered: July 10, 2003 7:42 AM
Re: The C++ Style Sweet Spot
October 18, 2003 8:38 AM      
> The C++ examples seem to be C style. To contrast, here is
> a Fibonachi class

Please email it to dada@perl.it
(Aldo can only post code that he receives direct from the author)

He'll be so overwhelmed that he might actually get around to updating the website ;-)
Isaac
Posts: 51 / Nickname: igouy / Registered: July 10, 2003 7:42 AM
Re: The C++ Style Sweet Spot
October 18, 2003 8:52 AM      
Seemed to me like a combination of Objects and ADTs
- simple class (representation and invariant)
- ADT (functions that act on the object)
Joe
Posts: 15 / Nickname: jcheng / Registered: October 16, 2002 8:08 AM
Re: integer *should* be part of a class hierarchy
October 19, 2003 7:59 AM      
>> Ah, but you are missing the crucial point to languages like Ruby and Python: use the best tool for the job. You do most of the coding in a nice programmner-friendly and very productive language and use libraries (eg. NumPy http://www.python.org/topics/scicomp/numpy.html), or write C extensions for just those parts that need the blazing performance. <<

I very much understand that... don't get me wrong, I use Ruby all the time. I am not trying to belittle the usefulness of those languages in the real world. All I am saying is that Gosling et al's decision not to make Java primitives objects is a reasonable tradeoff for some set of users/problems.

For example, some programmers would rather implement a project in one "fast enough" language than in a combination of a really slow and really fast one--especially if binary cross-platform compatibility is a requirement.
Joe
Posts: 15 / Nickname: jcheng / Registered: October 16, 2002 8:08 AM
Re: integer *should* be part of a class hierarchy
October 19, 2003 8:18 AM      
> Generics work for strongly-typed collections, not
> heterogeneous ones. I suppose in C++ you could always have
> a collection of void pointers, which amounts to the same
> thing but somehow seems uglier to me.

Absolutely. I didn't consider heterogeneous collections; usually when I hear this line of thinking it's referring to homogeneous collections.

As for the rest of your post, I thought your original post was talking about integer-as-object in a much more full sense--as in, undistinguishable from other class-based objects in both appearance and implementation, in the way that say String is for example. If .NET's type system meets your definition of integer-as-object, then I completely agree with you... working with ints is much nicer in C# than Java, arguably as "elegant", and the performance is the same.
Isaac
Posts: 51 / Nickname: igouy / Registered: July 10, 2003 7:42 AM
Re: integer *should* be part of a class hierarchy
October 19, 2003 2:19 PM      
>Generics work for strongly-typed collections, not
>heterogeneous ones. I suppose in C++ you could always have
>a collection of void pointers, which amounts to the same
>thing but somehow seems uglier to me.
>
> Absolutely. I didn't consider heterogeneous collections;
> usually when I hear this line of thinking it's referring
> to homogeneous collections.

Any examples of the need to work with heterogeneous collections? I'm struggling to remember an example - even in Smalltalk the collection elements seemed tightly related.
Julian
Posts: 1 / Nickname: julianr / Registered: October 21, 2003 1:04 AM
Re: integer *should* be part of a class hierarchy
October 21, 2003 5:47 AM      
> Generics work for strongly-typed collections, not
> heterogeneous ones. I suppose in C++ you could always have
> a collection of void pointers, which amounts to the same
> thing but somehow seems uglier to me.

You can also use a collection of boost::any objects when the stored objects don't share the same base class. It's not perfect, but it's safe, and a lot cleaner than using void pointers (in fact, I use boost::any for almost everything that would otherwise have been a void*).

If you would make everything polymorphic in C++, would you still keep value semantics? I think the clear value/pointer semantics of C++ are one of its strengths.
Bjarne
Posts: 48 / Nickname: bjarne / Registered: October 17, 2003 3:32 AM
Re: integer *should* be part of a class hierarchy
October 21, 2003 10:00 AM      
> > Generics work for strongly-typed collections, not
> > heterogeneous ones. I suppose in C++ you could always
> have
> > a collection of void pointers, which amounts to the
> same
> > thing but somehow seems uglier to me.
>
> You can also use a collection of boost::any objects when
> the stored objects don't share the same base class. It's
> not perfect, but it's safe, and a lot cleaner than using
> void pointers (in fact, I use boost::any for almost
> everything that would otherwise have been a void*).

For a slightly more general answer, se my FAQ: http://www.research.att.com/~bs/bs_faq2.html#containers

A collection of void* is very rarely a good answer.
66 posts on 5 pages.