Out of the (C++) loop

Goto considered risible

Stob Hi Verity, are we up for some more frolics and fun?

Nope. It's a spot test today. Using your neatest handwriting, write out a standard C++ loop on the nursery blackboard. No copying. This will count towards your final grade.

Joy. What brought this on? Oh, ok – gimme the chalk, let's get it over with:


for (int i = 0; i < ARRAY_SIZE; i++)
{
  // do something to an array...

You should be ashamed of yourself. That code is a crime against modern C++. Come out with something like that down the ACCU, you could find yourself sentenced to six months mentoring Linus Torvalds through his Visual Basic breakdown.

Ok, clever clogs, so what's wrong with it?

Let me count the ways:

  • You've used < 'less than' in the test instead of != 'not equals'. These days you are always supposed to test for inequality, in case you later 'port' the code to use iterators.

But I LIKE the < test. It's a nice overrun-preventing sandbank at the back end of the loop, so that one doesn't have to be too careful about getting the stopping condition exactly right. Know what I mean?

Shush, child. There may be colleagues or employers reading.

  • You've used a post increment i++ instead of a pre increment ++i, thus incurring the certain cost of an unnecessary copy.

Don't be silly, it's an int! The day they change the language name to ++C, that's the day I'll start taking pre-incrementing seriously.

  • That ARRAY_SIZE is a disgusting #define that you are hiding somewhere in the header.

You can't prove that. It might be a pukka const for all you know.

  • You have used a C-style array rather than a container class, thus depriving yourself of the STL's sanity checks and versatility and potential performance gains and what not.

Just because it says 'array' in the comment, that doesn't signify anything. I'm pretty sure I've updated it to a vector, now you mention it. And anyway, I'm suspicious about STL containers going faster 'in theory'. Wasn't it OS/2 that had a filing system that ran ten times faster than anything else, provided you remembered to run it 'in theory' rather than 'in practice'?

  • You have used an int rather than an iterator to get at the elements of your structure, meaning you are restricted to containers that support random access.

See, the thing is, iterator declarations don't half make a mess of the code. They are such ugly, prickly things; all full of :: and <>. And you always have to make two, one for the index and the one to hold end marker, which makes it worse.

  • The clincher. You shouldn't have been using a loop at all. You should be using an algorithm

Here we go. Finally we cut to the chase. I've been waiting for this.

Don't take my word for it. Listen to the voices of the gods. Prefer algorithms to loopsMariella Frostrup, 2000.

Surely 'Bjarne Stroustrup'?

Prefer algorithm calls to hand-written loopsMeyers, 2001. Prefer algorithm calls to handwritten loops – Sutter & Alexandrescu, 2005.

We are the legion of the BeastThe Ood, 2006.

I seem to sense that you have some issues...

I should cocoa! You come barging in here, with your metropolitan mannerisms...

...but there's no need. Because I agree with you.

Huh? You do?

Oh yes. I can never get algorithms to match the problem I have in hand. I sit there looking at the list, wondering if I should be using adjacent_find or remove_copy_if, but they always have this quality of not quite doing what I want...

Yes! Yes! That's right! It's even worse than those bloody awful find_last_but_one_not_of functions you get with substrings!

...so I look at those adapters and binders and try to bodge it together with a bind2nd here and a greater_equal there...

This is just what happens to me! And then you give up and write a whole new functor thingy, just for this one loop?

And then I give up and write a new functor, hidden guiltily in the middle of the implementation of the class I am really working on, thereby blowing the whole reusability thing to smithereens. And messing up the readability of the code. And making a complete pickle of the flow. AND sending the performance to hell on a handcart too, for all I know.

Assuming you can get the sod to compile!

Yeah, you wrestle for 20 minutes with the bizarre error messages the compiler pushes out when you're mucking about with templates. Then you notice that the exercise has taken you about nine times as long as it would to bash in an ordinary loop. You're all cross and hot and bothered, because you've just wasted half an hour trying to do the Right Thing, and the result is a complete and utter dog's breakfast.

Anybody who comes round and tells me that this is intrinsically more reliable than a hand-coded loop will get such a slap...

Oh God! It's such a relief! All these years, I thought it was just me!

There, there. Never mind. It's all going to be all right. Would you like to borrow my hanky?

Thanks. But Verity, what are we to do? If the C++ overlords believe that the construction of nearly every loop should be a sort of inline Sudoku puzzle, surely the problem must be that we are simply too stupid to use the language?

Well, I reckon I'm pretty handy, actually. Fancy myself ten bob each way, as a programmer. And surely the very fact that you are a Reg reader implicitly puts you above the top quartile, if not decile, of both taste and coding competence.

I don't think that we are the problem here. We are good workers blaming our tool.

Damn right, sister! So is there some sort of workaround?

Well, the fabulous Boost boys have this library that lets you support llama functions...

You perhaps mean 'lambda' functions...

...which kind of lets you bodge in the code where it belongs, in the loop. So to do a for loop within a for_each, to steal an example from the Boost site

int a[5][10]; int i;
for_each(a, a+5,
  for_loop(var(i)=0, var(i)<10, ++var(i),
           _1[var(i)] += 1));

Hmm, s'pose that looks more like it.

It does, but I say it's still too hard. If you look at their examples, you'll see it gets pretty hairy and ugly as soon as you need to do anything even slightly complicated.

I take it you have an alternative solution?

Indeed. If we must write lambda functions to use the standard library properly, then the language should bloody well support lambda functions directly, straight out of the box. Proper, ordinary, C++; not using some near-C++ ersatz syntax that geniuses have toiled over for years using macro and template tricks to make it slightly less ghastly.

Let the compiler take the strain. If JavaScript can do it, C++ should be able to too. Ask any Joel.

Sounds fab. Where's your modified version of gcc that supports this stuff?

<cough> I see myself as more of an Ideas Person. I leave mere implementation details to Mariella & co.

Quelle surprise. To end things on a more positive note, how about an example of an iterative algorithm that's easy-to-use, neat, quick and really does the business?

Ok, how about this:

Have somebody else hold your glass for you.
Take one sip of liquid or, in severe cases, two.

Eh?

It's a cure for hiccups. Works 100 per cent, at the pub, work and even home. Try it.

Verity, you are too good to me.

I know. ®

Sponsored: Network DDoS protection