Programmers: please learn when to not use while loops

C and C++ do not have a “modulo operator”, they have a “remainder operator” (in spite of the fact that the index to K&R 2[sup]nd[/sup] ed. calls ‘%’ modulus). As such, a legal result of x % 2 is -1.

Not if the integer x is always positive, which I have already stated. For those effects, the % operator being called modulo (as it is in every textbook I’ve seen on the subject) works perfectly well for those purposes.

catsix, I like you a lot where I’ve run across you on the boards. But I disagree with you here.

I’ve been programming since 1977. Over the years I’ve seen the standards of coding by what you might call an “average” programmer go down steadily, probably because a) I’ve gotten older, more experienced, and my standards have risen, and b) because an increasing number of people have gotten into the field. I did datacomm support programming for seven years. This was far and away the most difficult programming I’ve done (maintaining code written by others can be far tougher than writing it from scratch!), and far and away the most educational programming I’ve done. It taught me to be fanatical about error handling, comments, and belt-and-suspenders coding. If that means the occasional block of unnecessary code, so be it - it beats the hell out of your program taking off into lulu land because of something totally unexpected occurring and not having a major effect until some seventeen blocks down the road!

I’m sure you’re a terrific teacher, but I hate like hell the thought that one of the first lessons your students are getting is to avoid “better safe than sorry.” My experience has been that the newer, less experienced programmers are all to willing to leave out anything that doesn’t follow the intended, expected path. More experienced programmers, while by and large less likely simply by virtue of their experience to make as many errors, are far more likely to take into account the fact that things don’t always work as expected or intended. Your example of a mod(2) is pretty compelling, but how often in the real world are things that cut and dried? Wouldn’t it be better for your students to learn that a few lines handling a ridiculously unexpected result (or what they consider to be such!) can prevent a lot of angst someday?

Me, I’ll take an overly cautious, verbose programmer over someone who packs things into the fewest possible lines any day. I know the latter is not what you’re recommending, but I’m afraid it may be what your students are learning.

Egad! I can’t believe I missed those posts. Sigh. Serves me right for checking on threads instead of programming.

While I couldn’t resist nitpicking everything , I get the impression he’s looking at genuinely redundant code.

The if (x) else (!x) else thing - that doesn’t look like being cautious it really does look like sloppy thinking (I should know :)). Sometimes it makes sense, eg. if (x<0) else if (0<x<4) else… it’s safer. Of course, I don’t know quite what he’s teaching, but that’s the impression I get.

What they’re learning is to write code that works and handles exceptions without going off into writing and documenting a lot of lines of code that are never used, or come into play at all.

I don’t have a problem with due caution, but I do have a problem with seeing a program that is three times as long as it should be because someone used undue and overzealous caution, especially when I have to read, decipher, and help them debug all of those lines.

You can bet your ass if the choices are x or !x, and I see a switch/case arrangement where they should be doing something in case 0 and showing an error message in every other case that has thirty or forty cases defined, I’m going to have a shit fit at them, not only because they have written that many lines of bad and/or redundant code, but that they’ve spent hours doing that, and then asking for a deadline extension because they haven’t even gotten to the real crux of the problem they were asked to solve.

I want them to be sure that error conditions are covered, or that unexpected data is covered, while at the same time not coding like a redundant assclown and writing 600 lines where 100 will more than do the job. If that offends you, or you think that I’m not teaching them properly, then I guess we’ll have to agree to disagree.

After all, I already have to slog through fifteen variable declarations in a program that uses at most, four variables, and looks like this:

int a = 0; //declare variable a
int b = 0; //declare variable b

int o = 0; //declare variable o

Then I have to explain to them that while they are actually commenting code, and that is good, they should make the comments meaningful, and that naming every variable in a program after a letter of the alphabet is not a good idea because 70 lines into the program they will very likely have no idea what the hell variable q was for.

I’m a she, but yes, that’s what I was talking about. For example, I had a student who would do things like initialize a counter variable at the beginning of a program, then initialize it again directly before the for(i = 0; i < 20; i++) line. When I asked that student why they had initialized ‘i’ three times, especially as it was used nowhere else in 60odd lines of code, he replied ‘In case the computer didn’t understand it the first time.’

So yes, I want them to be safe, just not tinfoil helmet safe.



for (x=0;x<100;x++)
{
    for (y=0;y<100;y++)
    {
        for (z=0;z<100;z++)
        {
             if (DidFindNugget(x,y,z))
             {
                  goto found;
              }
         }
      }
}

DidNotFindFunc();

found:


There ya go :slight_smile:

I have gotten myself in big trouble forgetting the DDL autocommit feature. I have been doing long test and modifing data knowing in the back of my head that I was just going to rollback when I finish the test. Then in the middle somebody comes up and says there is a new user who needs a data table. I happily create the table for them on the current session, then go back to my testing.

:smack: Okay, put on best confused face and tell boss there is an unknown problem with the production data, and It’s best to load from the last backups.

As for gotos, here’s another case where I’ve blanked on a better way of doing it:



switch (x) {
case 0:
         //do some stuff
         goto otherstuff;
case 1:
         // do some stuff that's different than case 0
otherstuff:
         //do otherstuff;
         break;
//5 other cases here
}


Sure, I can make an “otherstuff” funciton and call it in both cases, but sometimes you can’t take the overhead of another function call…

-lv

One semester, I had a student in my C++ class come to me about an assignment and asked…

“My code is about 3000 lines long so far. Do you think I’m making it too hard?”

Monstre: “Considering that my solution is about a page and a half when printed out… um…”

:smiley:

In C/C++, you can state even more broadly – all loops can be re-written as any of the other loops - pick your favorite… (except for the effect of declaring a loop counter in the for-header, which has scope for all runs of the loop, but not outside… with while loops, gotta do it before the loop begins)

But I still encourage my students to use good practices and use for-loops for counting situations and while or do/while for logical exit situations. I don’t expect them all to program as efficiently as possible yet – they’re learning. But have to try to discourage bad habits and encourage good ones.

The only situation in which I’d disagree with this is when the different wrong values of x indicate different errors. If that’s the case, then it may be appropriate to have the switch field other values. Or it may make sense to handle it in the error handler - depends on the scope of the meaningful info to report about the error.

Yo, ease back there a little, girl! I’m not attacking you, and I don’t deserve that (the redundant assclown bit), okay?

And Lord, I have run into this:

and what has bugged me even worse, I’ve seen error handling that actually ended up giving the user less information than letting the error go unhandled would! And with the magic of cut and paste, promulgate that same error handling throughout numerous routines in the system!

I understand the urge :D, but yes, it should be resisted.

But I still would prefer a brief journey into tinfoil hat land than the blythe overconfidence I usually see in young (and regrettably, not so young) programmers. Yes, longer code can be a nuisance to read. But it can be well worth it.

Are those the same folks who insist on burying a commit in the bowels of their stored procedures?
I regularly pound anyone who would do such an unsportsmanlike thing. Typically this surfaces when you are writing code that is nested forty layers deep and can’t figure out why your carefully-crafted test data all got permanently updated.

Once again we see that programming is almost as much art as it is science, so these issues will never be fully resolved.

I meant redundant assclown students who declare exactly the same variable 3 times within 3 contiguous lines.

Sometimes it can.

Times like

switch(x)
case 0: do good stuff
case 1: you entered bad data
case 2: you entered bad data
case 3: you entered bad data
case 4: you entered bad data

case 100: you entered bad data

not so good.

I once had a student ask me what the maximum possible integer value in C++ was so that he could properly code enough case statements to handle the error. He had coded in all of the valid menu choices to do exactly what they should have. Then he wanted to code every invalid choice. He actually said to me ‘When I’m done with the integers, should I move on to floats?’

I weep.

I have instructed them against using error messages like ‘Error. Unknown error occurs.’

I also have students who will do something like calculate a netNumberOfItems throughout an entire program, get to display line and cout << "The total is: " << total << endl;

They have also in the same program declared The, total, and is as variables.

I had another one who attempted to write code in paragraphs. He asked on his first programming assignment if I wanted it in MLA format.

Although the question that takes the cake is the time the guy who’d already taken two previous programming classes (other professors) and was ten weeks into my twelve week course asked me ‘What is a variable?’

ACK! Thpttt…

My stock answer to things like that is “the size of an int is machine dependent”. And then I warn them that while most machines today have 4 byte ints, one day the standard for ints will likely be bigger. Make it work for ANY integer.

I often put a bonus problem on my first test that asks students to write a function that adds the digits of an integer, or reverses them, or something like that. Mostly get attempts laid out like this:



if (num > 0 && num < 10)    // one digit
{
    // blah blah blah
}
else if (num >= 10 && num < 100)   // two digits
{
   // blah blah blah
}
else if (num >=100 && num < 1000)  // three digits
{
   //  blah blah blah
}
else if....


sob

Even worse, I usually give an example call to illustrate what is expected, something like: “For example, if the following call is made: Reverse(3957); then
the function should return the value 7593”. And then, half of them code it for ONLY four-digit numbers.

So since we’re on the subject of coding peeves, here’s a big one for me. People who cannot seem to distinguish between a specification and an example. Just because you made ONE EXAMPLE I gave you work doesn’t mean you met the specification.

Have also encountered way too much of the useless comment thing. I tell them in class: “The following is what I refer to as a ‘Well, DUH!’ comment:”



  temp = x;   // assign x into temp


And if you’re my student, and you ask me, “I submitted the program before the due date, but today (after the due date) I just remembered that I forgot to go back and put any comments in. Can I still do that and submit it without getting a late penalty?”… if you ask me that… well, I hope you can run fast. :smiley:

From The Jargon File:

can’t happen

The traditional program comment for code executed under a condition that should never be true, for example a file size computed as negative. Often, such a condition being true indicates data corruption or a faulty algorithm; it is almost always handled by emitting a fatal error message and terminating or crashing, since there is little else that can be done. Some case variant of “can't happen” is also often the text emitted if the ‘impossible’ error actually happens! Although “can't happen” events are genuinely infrequent in production code, programmers wise enough to check for them habitually are often surprised at how frequently they are triggered during development and how many headaches checking for them turns out to head off. See also firewall code (sense 2).

A couple thoughts. First, on how to get code to properly display on the SDMB. vBulletin supports a [ CODE ] tag(sans spaces). Anything in it will be treated as a code fragment and the formatting not jacked with. A straight copy-paste of your code fragment into the [ CODE ] tag produces the following.


for (x=0;x<100;x++)
{
    for (y=0;y<100;y++)
    {
        for (z=0;z<100;z++)
        {
             if (DidFindNugget(x,y,z))
             {
                  goto found;
              }
         }
      }
}

DidNotFindFunc();

found:

I don’t have a problem with a goto here, but it is getting harder and harder to justify them and some languages are reportedly not even offering them. I’m not sure what language or flavor of language you’re writing in, so efficiencies of the different control structures obviously come into play. What you’re doing is a sentinel controlled loop with two sentinels. One a bounds on the number of attempts, another the success/failure of the innermost conditional. So it could be done with returns. Something like this.


for (x=0;x<100;x++)
{
    for (y=0;y<100;y++)
    {
        for (z=0;z<100;z++)
        {
             if (DidFindNugget(x,y,z))
             {
                  return $Yippee_There's_Gold_In_This_Here_Spot;
              }
         }
        if ($Yippee_There's_Gold_In_This_Here_Spot)
        {
            return $Yippee_There's_Gold_In_This_Here_Spot;
        }
    }
    if ($Yippee_There's_Gold_In_This_Here_Spot)
    {
        return $Yippee_There's_Gold_In_This_Here_Spot;
    }
}

if (!$Yippee_There's_Gold_In_This_Here_Spot)
{
    DidNotFindFunc();
}

Your language or other library functions may offer ways to speed this up and eliminate the redundant conditionals by inheriting the return back up the chain.

I’m thinking there is a way to do all that within one loop using modulo arithmetic. Count high enough and have each co-ordinance determined by the remainder from a different modulus of the big number, so you get offsets. Modulus is a pretty fast operation in most languages.

Enjoy,
Steven

I used to get this in english. When asked to define a word I’d sound like an idiot because I’d try to define it while everyone else shouted examples.

My advice: make it explicit (if you don’t already). Say “It should reverse the order of the digits of any positive integer. Here is an example, but it has to work in other places as well. If it ends with a zero, it’s ok for this to be dropped when it becomes leading.”

Did anyone try converting it to a string?

Ya wanna talk about bad code, I’ll give you bad code… I just fired a programmer who wrote:

if(Key == ‘0’)
printf(“The Key was ‘0’”);
else if(Key == ‘1’)
printf(“The Key was ‘1’”);

all the way 0 through 9. When I asked what would happen if she got a non-numeric key, she told me she hadn’t had time to tidy up the code and didn’t realize that there would be a code review…

How about this instead



bool CheckForNugget()
{
  for (x=0;x<100;x++)
  {
    for (y=0;y<100;y++)
    {
        for (z=0;z<100;z++)
        {
             if (DidFindNugget(x,y,z))
             {
                  return true;
              }
         }
      }
  }

  return false;
}

if(!CheckForNugget())
{
   DidNotFindFunc();
}

There’s always an alternative to goto. Though I have no problem with the former either.