2022-09-19

Sworn enemies?

Even the pious Scots, locked throughout history in a long-drawn-out battle with their arch-enemies the Scots, managed a few burnings to while away the long winter evenings.
Terry Prattchet

The last couple of weeks have seen me drawn into another skirmish in the defining contest of the information-age workplace: schedule and cost estimation for development projects.

Managers of course need to know what things will cost and when they will be done. Developers know from hard won experience that it is not possible to know either of those things before you start the work. The closest things to reliable soluions that have been developed seem to fall into two rough categories:

  • Process-heavy mechanisms where you front-load the detailed design and get a moderately reliable estimate of the total cost and time when you're 15-20% into the effort, but entailing some risk of a complete failure
  • Agile methods which get to something early and evolve ever closer to the desired product over time and might be alleged to generate a reasonable approximation to the spec given the schedule and budget allow

Now, our client has allowed us to pursure the latter strategy while my project was an exploration of possibiliies (and just as well, it's what I know how to do), but now that it is a product in actual use, they are asking for or even insisting on firm commitments on both time and money. Sigh. Best guess and a generous pad it is.

2022-09-09

Algorithms of adjacency

Today at work I wanted to test the relationships between the contents of a vector in a sequential manner: cell i+1 should have this relationship to cell i kind of thing.

Question:
Does the algorithm header support that?
Answer:
Yes, two ways.
Question:
Can you tell just by reading a list of the calls?
Answer:
Maybe. How much attention are you paying to the signatures?

The key word here is "adjacent". Two of the algorithm header routines have that word in their name: adjacent_find and adjacent_differernce, and both of them have an overload where you supply a binary operator.1

Of course, the issue of difficult naming rears its ugly head here: adjacent_difference can perform any computation it wants to create the output values written (i.e. it is a version of the pairwise overloads of transform specialized for adjacent cells). Kate Gregory's story about partial_sort_copy is relevant here.

So that's cool: what I wanted was right there.

Only I started thinking2 about the other things I might want to do this way, and I noticed that the library doesn't give me a built in way to count pairs that meet some predicate. Of course I can build it out of adjacent_find fairly easily,3 but it's not baked in.

My problem at work? Well, that was test code, and the predicate was a lot clearer if you knew where you were in the container you were, so in the end I wrote for (size_t i=1; i<container.size(); ++i) { const auto thing1 = container[i-1]; const auto thing2 = container[i]; // ... } The library routines are great, but knowing when to not use them is great, too.


1 You can also acheive same two operations by using mismatch and transform, though I feel the "adjacent" named routines make the intent clearer. I takes a moment to suss out the meaning of something like const auto [i2, i1] = std::mismatch(++container.begin(), container.end(), container.begin(), my_comparator); aferall, while adjacent_find is pretty plain (though you'll have to parse the behavior of the supplied comparator in either case).

2 I know. I know. That was my mistake.

3 If I had more spare time I'd poke ino some of he standard library implementations to see if people build count_if from find.