Tuesday, November 8, 2016

Singular and Plural Output -- One Lump Or Two

This particular blog post teeters on that fine line of ridiculously obvious and pure genius.

It's not too uncommon to provide output of a particular data structure that can take the form of singular or plural content.  Because we're often in a rush, we sometimes sacrifice a more thoroughly thought out implementation for speed of implementation, sloppy but fast.



The result, duplicating assignment of output assignments like this:
  if ( list.size() <= 1)
  {
    printf("(%s:%d) found %ld identifier %s\n",__FILE__,__LINE__,list.size(),oss.str().c_str());
  }
  else
  {
    printf("(%s:%d) found %ld identifiers %s\n",__FILE__,__LINE__,list.size(),oss.str().c_str());
  }

Copy-n-pasted statements are notorious for falling out of sync and can complicate the intended usage (e.g. say overlooking one of the cases when searching through the logs).

Or perhaps worse, simply ignoring or manipulating grammar to fit for both the plural and singular content.
    printf("(%s:%d) found identifier list: %s\n",__FILE__,__LINE__,oss.str().c_str());

But if you take a breath you can satisfy both plural and singularity output, which often is simply accomplished by adding an 's' to a word in the string, like this:
  printf("(%s:%d) found %ld identifier%s %s\n",__FILE__,__LINE__,list.size(),list.size()<=1 ? "": "s", oss.str().c_str());


Full source code example follows.  I've taken some liberties mixing C & C++ syntax for convenience and to demonstrate the principle rather than using solid coding practices.  The same principle can be applies to pure-C or pure-C++ implementations.

#include <stdio.h>
#include <vector>
#include <iostream>
#include <sstream>
#include <string>
#include <algorithm>
#include <iterator>

typedef std::vector<int> List;
typedef std::ostringstream ListString;

void log(const List& list)
{
  ListString oss;
  std::copy(list.begin(), list.end(), std::ostream_iterator<int>(oss, " "));

  if ( list.size() <= 1)
  {
    printf("(%s:%d) found %ld identifier %s\n",__FILE__,__LINE__,list.size(),oss.str().c_str());
  }
  else
  {
    printf("(%s:%d) found %ld identifiers %s\n",__FILE__,__LINE__,list.size(),oss.str().c_str());
  }
}

void log2(const List& list)
{
  ListString oss;
  std::copy(list.begin(), list.end(), std::ostream_iterator<int>(oss, " "));
  printf("(%s:%d) found %ld identifier%s %s\n",__FILE__,__LINE__,list.size(),list.size()<=1 ? "": "s", oss.str().c_str());
}

int main(int argc, char* argv[])
{
  printf("(%s:%d) main process initializing\n",__FILE__,__LINE__);
  static const int arr[] = {1,1,2,3,5,8,13,21,34};
  static int arrSize=sizeof(arr)/sizeof(arr[0]);

  List list1(arr,arr+1);
  List list2(arr,arr+arrSize);

  log(list1);
  log(list2);

  log2(list1);
  log2(list2);
  printf("(%s:%d) main process terminating\n",__FILE__,__LINE__);
}

No comments:

Post a Comment