Some loops don't have a simple beginning or ending. I wonder what your favorite techniques for avoiding or working around the problems are. An example is the pseudo-code loop under GeneticAlgorithm. Notice how "evaluate each individual's fitness" is in there twice. This is anti-OnceAndOnlyOnce. To fix it we need to jump out in the middle, which ruins top-or-bottom loop conditions, or requires a half-loop.
So make a method IsFit?(anItem), and put the condition there.
It can break up the mental flow in my opinion. Evaluating individuals and the ending condition may not be that closely related. Sometimes there are multiple independent steps before the loop exit test. I don't like creating small functions unless it fixes OnceAndOnlyOnce. I suppose this is a case of that, but it still feels like there should be another approach. I don't like the idea of making another function JUST because it does not fit nicely into loops. (Some believe heavily in lots of small functions/methods. But, I am not one. See LongFunctions.) Maybe I am just over-thinking the issue. But I do encounter it fairly often and have not found a satisfactory solution other than just creating a flag:
reloop = true; while (reloop) { .... }But this may require a bunch of IF statements inside. The general pattern for the problem usually resembles:
initialize stuff begin loop some complex calculation if some_condition_based_on_complex_calculation then exit loop end if primary loop processing end loopA variation is:
initialize stuff begin loop some complex calculation if some_condition_based_on_complex_calculation and not first pass then exit loop end if primary loop processing end loopIt doesn't break flow... it enables it. IsFit?(anItem) is far clearer and easier to read and comprehend than a messy chained together boolean statement with 5 conditions in it. Even it were only used once, I'd break it out to clarify the code and avoid the need for a comment explaining what it does. Programming is all about creating small functions, until you accept that, you'll overthink everything and spend all your time chasing your tail! Using a flag, breaking the loop, jumping somewhere to evaluate, and then re-entering the loop is insane, you're reinventing your own private version of a method call, just use the language and write a method and call it. You're a programmer, methods are your tools, classes are your tools, don't be afraid to use them, that's why they're there.
This appears to be a repeat of the HolyWar in LongFunctionsDiscussion. No need to revisit those here. The bottom line of those debates is that it is a personal preference or dependent on conflicting psychology models. My question is thus addressed to fellow non-short-functioneers.
Maybe, but you're asking about a problem with messy conditions... this is a problem fixed by shorter functions, in fact, this is a problem we don't have because we've learned to learn, and not hang on to bad habits that create silly problems like this. You can't fix long functions, you simply avoid them. The best question is why are you so afraid of a function, it won't bite you know, and you'll feel better later for doing it. And if it doesn't fit the way you think, then fix the way you think, we call that learning, the best solution to a problem is learning how to avoid it in the first place, don't be so stubborn about learning to think differently, that's where all real progress is made.
Re: "And if it doesn't fit the way you think, then fix the way you think": Perhaps it is YOU who thinks wrong. Non-short functions are only messy if you have not learned how to grok them. Two can play this game. Dammit, you dragged me into the "shorty" debate again.
If it were me who thinks wrong, I would be asking for help, but I'm not, I consider this stuff trivial. You are having issues because you are holding onto practices that create them, your ego is getting in the way. Believe me, my ego's gotten in my way many a time, and the outcome is always the same, eventually I learn to set it aside and learn to think differently to get to the next level. Over the years, I've learned to put my ego aside sooner and just learn the new method, it's a far faster way to learn. Use short methods, you won't have any of these problems, in fact, there's a whole list problems that simply disappear with shorter methods, it is a better way. Go read the JavaHotDraw? sources for an example of how clean concise and clear this style of programming is.
{It has nothing to do with my ego. Lots of short functions do not help me grok code. Honest.}
This is a HolyWar; neither of you are going to convince the other of your position. Try refactoring to answer the condition from both points of view. -- AnonymousDonor
I hate to put fuel on this fire but.... When you complain "There must be a better way!", you must be open to a suggestion that "Hey, yes, there is a better way; here it is!".
And, on another note: here's another solution, which depends on some language support of co-routines or tail-calls: each stage in the loop is its own function. The end of each function returns the result of calling the next function. The conditional statement is the only one which could potentially break the loop, by directly returning a value:
(let-q //or whichever one allows this type of thing ( (someComplexCalculation (lambda () (some complex calculation implementation, return (theConditional result))) (theConditional (lambda (result) (if(result) return blah else return (standardProcessing)) (standardProcessing (lambda () (your standard processing, return (someComplexCalculation))) ) (initialization) (someComplexCalculation) )But, we know how much you like small functions... we can only imagine how you'll like this :) -- WilliamUnderwood
Exactly, lambda's are a small function lovers best friend. Top, you got to understand that when you ask for help, you are placing yourself in the position of student, when someone shows you a solution to your problem, learn from it, don't reject it because it's "not the way you think". Obviously its not the way you think, because your thinking can't solve the problem, or you wouldn't be asking. All advanced programming techniques will bend your mind and force you to see things in a new light, but if you don't allow your mind to change the way it thinks, you won't ever learn anything. I've read dozens and dozens of your code samples, and your site, and no offence, but most of the people you have regular discussions with here, are far more advanced programmers than you are, Mr Underwood for example, or Costin, or Doug, etc... so try and learn something from them rather than arguing with them about things they know far more about.
If I get used to the high-fallutin' stuff, then it will be hard to write code that typical companies want. I have already been told that I use too much indirection and too many functions. Remember, companies want plug-compatible developers. Anyhow, how is the above objectively better than breaking out of the loop from the middle? So far it seems like it fits DoTheSimplestThingThatCouldPossiblyWork. "It is better because I am smarter than you" smacks of ArgumentFromAuthority. I believe in the scientific process and open evidence. Perhaps deep-down psychological mind alterations do improve stuff, but if you cannot articulate precisely why, then you also have some homework. Maybe the best programmers are the worse articulators.
ChooseInitialPopulation?(); EvaluateEachIndividualsFitness?(); DeterminePopulationsAverageFitness?(); repeat SelectBestRankingIndividual?(); MatePairsAtRandom?(); ApplyCrossoverOperator?(); ApplyMutationOperator?(); EvaluateEachIndividualsFitness?(); DeterminePopulationsAverageFitness?(); until terminating condition (e.g. until at least one individual has the desired fitness or enough generations have passed)''So I don't see any violations of OnceAndOnlyOnce, or any potential problems, because they're just method calls, EvaluateEachIndividualsFitness? is only implemented once, thus no duplication. And the overall algorithm is vastly clearer than if it were implemented inline forcing you to parse all that code mentally. You say you believe in open evidence, but you obviously don't, you only want to justify your current position. If you believed in open evidence, it should be blindly obvious why the above chain of method calls is better than one big function with all the implementation inline. If you can't see that, then you don't really have the capability to be a great programmer.
I guess not. I don't see it. I bow to your greatness. The emperor has spiffy clothes.
You see, I have nothing to prove to you, you're the one asking questions, it's up to you to evaluate the evidence, you'd be wise to try and forget what you think you know when doing so, or you're not really evaluating it. No one is going to offer up any solutions you'll be pleased with, that should make you wonder if it isn't you who needs to learn a thing or two!
Maybe. It is just that I have experience where I change one part and forget to change the matching part that (seems) duplicated above the loop. I usually try to find a way to factor such that I don't have to face such apparent duplication; but if it is good and there for a purpose, then I guess forgetting to change both of the matching parts is my own limitation. However, couldn't anyone use that to justify ignoring OnceAndOnlyOnce? "If you forget to visit each copy, then the fault is you, not factoring."
If the structure of the algorithm is:
initialize stuff begin loop some complex calculation if some_condition_based_on_complex_calculation then exit loop end if primary loop processing end loop(as stated above) then why shouldn't that also be the structure of the code? E.g.
while (true) { result = ComplexCalculation(); if (result.finished) break; ... primary loop processing ... }I used to feel uneasy when I wrote this, since I felt that writing "while (true)" was not "proper" coding. But, I got over that when I realized that code which matches the underlying algorithm is the easiest to read.
There are many languages which provide a do{}loop structure with no condition built into the loop. The only exit is provided through a break statement. Don't feel bad about while(true) or for(;;) or even t:...:goto t. They have their uses. On another note realize that the pseudo-code given isn't the structure of the algorithm. It is a description of it. -- WilliamUnderwood
ForthLanguage allows for all sorts of loop messiness by allowing multiple WHILE loop exit tests anywhere within a BEGIN-REPEAT or BEGIN-UNTIL loop. You can even specify alternate loop exit paths with ELSE-THEN. Example on HexDumpInManyProgrammingLanguages.
See also LoopingConstructs.