Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

Im-Paired Programming


March 04: Im-Paired Programming)

"Um, you got a minute?" Kerry's quiet voice broke through my concentration. I sat back for a moment, disengaging my brain from the task at hand.

"Of course, young apprent..." I swung around. Seeing the look on Kerry's face, I changed my tone. "Aw, heck, the Guru's not around right now, there's no point in carrying on the shtick. 'Sup, Kerry?"

"Well, I'm having trouble following this function," he called up the source code he was working on:

<b>// $Author: Bob$
void f( const vector< T > & timers )
{
  vector < pair< string,
           pair< long, 
           pair< long, 
           pair< long,
           pair< bool,
           pair< bool, bool> > > > > > >
  infoReceived;

  for (int outputCount = 0; 
       outputCount < timers.size();
       ++outputCount) 
  {
    pair< string,
      pair< long,
      pair< long,
      pair< long,
      pair< bool, 
      pair< bool, bool> > > > > >
    newInfo;

    newInfo.first = 
      timers[ outputCount ].id_;
    newInfo.second.first = 
      timers[ outputCount ].hour_;
    newInfo.second.second.first = 
      timers[ outputCount ].minute_;
    newInfo.second.second.second
      .first = 
      timers[ outputCount ].second_;
    newInfo.second.second.second
      .second.first =
      timers[ outputCount ].state_;
    newInfo.second.second.second
      .second.second.first =
      timers[ outputCount ].direction_;
    newInfo.second.second.second
      .second.second.second =
     timers[ outputCount ].showTimeSinceEvent_;

     infoReceived.push_back ( newInfo);
  }</b>

"Whooeee, Bahb's really outdone himself this time," I muttered, loud enough to ensure that Wendy could hear me.

"Now what," she called over the cubicle wall.

"C'mon over, and I'll show you." When Wendy pulled up beside us, I pointed at the code.

"Oh, my," Wendy gasped after examining the screen, "that's gotta be a record for the worst use of a pair that I've ever seen."

"Wanna see the best part?" I didn't wait for her answer, but scrolled down to the second half of the function:

<b>  for (int timerCount = 0; 
       timerCount < infoReceived.size();
       ++timerCount) 
  {
    TimerInfo info;
    info.id_ = 
      infoReceived[ timerCount ]
      .first;
    info.hour_ =
      infoReceived[ timerCount ]
      .second.first;
    info.minute_ =
      infoReceived[ timerCount ]
      .second.second.first;
    info.second_ =
      infoReceived[ timerCount ]
      .second.second.second.first;
    info.isRunning_ =
      infoReceived[ timerCount ]
      .second.second.second.second
      .first;
    info.isCountingUp_ = 
    infoReceived[ timerCount ]
      .second.second.second.second
      .second.first;
    info.showTimeSinceEvent_ = 
      infoReceived[ timerCount ]
      .second.second.second.second
      .second.second;
    ProcessTimer( info );
  }</p>
} // end of f()</b>

"Um...I don't see..." Wendy paused a moment. "Hey, wait a second — the only reason he's creating and filling in the infoReceived vector is to iterate through it and pull out everything he just put in it — then he tosses the whole darn vector away."

"You got it," I crowed. "Not only is that mess of nested pairs horrendously ugly, but it is redundant to boot."

"Why is it so ugly?" Kerry put in.

"Well, look at how much trouble you had reading it," I pointed out. "Not to mention the brittleness of it. Look at that last line — six .second statements in a row. You have to keep very careful track of how many levels down you're going in the nest — one too few and you're wasted. Boom!"

"And," Wendy interjected, "there's also the code communication that the Guru's always harping on. Look at the declaration of infoReceived:"

  vector < pair< string,
           pair< long, 
           pair< long, 
           pair< long,
           pair< bool,
           pair< bool, bool> > > > > > >
  infoReceived;</b>

"All we know about the items stored in this vector is that it takes a string, three longs, and three bools. But what are they? What do they represent?"

"I, um, was wondering," Kerry interrupted, "about the declaration of the newInfo nested pairs, inside the for loop:"

<b>   pair< string,
        pair< long,
        pair< long,
        pair< long,
        pair< bool, 
        pair< bool, bool> > > > > >
    newInfo;</b>

"It looks a lot like the nested pairs that go into the infoReceived vector, so I thought maybe a typedef would help here?"

"Very good, young apprentice," the Guru's voice sounded behind us, as she closed her tome with her customary snap. The three of us jumped to varying degrees. "That would indeed be a good place to use a typedef, if indeed the monstrosity of these nested pairs were required in the first place. Let us ignore the redundancy of the second half of the function for a moment," she reached over and scrolled back to the top of the function, "and consider how to eliminate these nested pairs."

"Um..." Kerry faltered under the Guru's direct stare. "Could we maybe create a structure?"

"Excellent idea, apprentice. Please demonstrate." I slid aside, to let Kerry at the keyboard. After a few minutes, he typed:

<b>void f( const vector< T > & timers )
{
  struct IncomingTimeInfo
  {
    string id_;
    int hour_;
    int minute_;
    int second_;
    bool state_;
    bool direction_;
    bool showTimeSinceEvent_;
  };
  vector < IncomingTimeInfo >
    infoReceived;
  for (int outputCount = 0; 
       outputCount < timers.size();
       ++outputCount) 
  {
    IncomingTimeInfo newInfo;
    newInfo.id_ = 
      timers[ outputCount ].id_;</b>

"And so on, filling in the members as we iterate through," Kerry said as he turned back to us.

"Very good, apprentice. In general, I find that nesting pairs more than two or three levels deep becomes quickly unreadable and unmaintainable. It is wiser to create a structure to hold the values you need. I also preach that it is frequently wise to use a typedef for your containers." She reached across and modified Kerry's code slightly:

<b>typedef vector < IncomingTimeInfo >
    IncomingTimes;
IncomingTimes infoReceived;</b>

"The benefit is most pronounced when you need to declare an iterator for the container, as in:"

<b>IncomingTimes::iterator timer;</b>

"Now, as you have observed, the new IncomingTimeInfo struct is quite similar to the existing TimeInfo struct, and if we use it instead, we can eliminate the redundant, second loop and the local structure. Please revise the code accordingly, my young apprentice, and show me your writings." She turned and silently glided away.

Later that day, when I updated my code from the repository, I saw Kerry's revised function:

<b>void f( const vector< T > & timers )
{
  for (int outputCount = 0; 
       outputCount < timers.size();
       ++outputCount) 
  {
    TimerInfo info;
    info.id_ = 
      timers[ outputCount ].id_;
    info.hour_ =
      timers[ outputCount ].hour_;
    info.minute_ =
      timers[ outputCount ].minute_;
    info.second_ =
      timers[ outputCount ].second_;
    info.isRunning_ =
      timers[ outputCount ].state_;
    info.isCountingUp_ = 
      timers[ outputCount ].direction_;
    info.showTimeSinceEvent_ = 
     timers[ outputCount ].showTimeSinceEvent_;
    ProcessTimer( info );
  }
} // end of f() </b>


Herb Sutter (http://www.gotw.ca/) is convener of the ISO C++ Standards committee, author of Exceptional C++ and More Exceptional C++, and Visual C++ architect for Microsoft. Jim Hyslop is a senior software designer for Leitch Technology International. He can be reached at [email protected].



Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.