goto thread (split)

Discussion of chess software programming and technical issues.

Moderators: hgm, Rebel, chrisw

User avatar
sje
Posts: 4675
Joined: Mon Mar 13, 2006 7:43 pm

Re: Some statistics about promotions and underpromotions.

Post by sje »

lucasart wrote:
sje wrote:Even continue is bad.
With the same reasoning, break is also bad. After all continue and break are disguised goto statements, no?
Using break in any place else than as the last statement in a case body is ugly.

Similarly, having a return statement any place other than the last statement of a function is bad.

Symbolic's search has no recursion. There is the one routine Node() which has a big switch statement with each case being a different phase. The routine's main loop hits the switch each time through until the current phase is PhaseExit. At the top of the loop is is single check of a volatile boolean which, if triggered, sets the phase to PhaseExit. There is no unwinding as there is nothing to unwind. There is nothing hidden on the stack to deconstruct as there is no recursion. The search can be paused, and it can also be stopped and restarted at any phase at any depth.

A lot of chess programmers still use a recursive search because they've copied it out of a textbook or from someone else's program. If they would take the time to learn about the alternative of no recursion, then they just might a more elegant -- and possibly faster -- program.

I have not used a goto or the like in at least thirty years. There has never been any need.
User avatar
Don
Posts: 5106
Joined: Tue Apr 29, 2008 4:27 pm

Re: Some statistics about promotions and underpromotions.

Post by Don »

sje wrote:
lucasart wrote:
sje wrote:Even continue is bad.
With the same reasoning, break is also bad. After all continue and break are disguised goto statements, no?
Using break in any place else than as the last statement in a case body is ugly.

Similarly, having a return statement any place other than the last statement of a function is bad.
I don't believe in absolutes but it's a very good rule of thumb to avoid multiple returns. One exit point only is almost always a good policy for code readability. Sometimes it will happen that you need to do something just before returning from a function and if you have multiple exit points you must code this everywhere you do a return, a lot of code duplication and that is a generally a sign you are doing something wrong. Having said that I don't strictly adhere to this rule and it sometimes gets me into trouble.

Same principle with control statements but I'm a less strict about that as that never seems to get me into trouble so you will see break and continue statements in my code.

Symbolic's search has no recursion. There is the one routine Node() which has a big switch statement with each case being a different phase. The routine's main loop hits the switch each time through until the current phase is PhaseExit. At the top of the loop is is single check of a volatile boolean which, if triggered, sets the phase to PhaseExit. There is no unwinding as there is nothing to unwind. There is nothing hidden on the stack to deconstruct as there is no recursion. The search can be paused, and it can also be stopped and restarted at any phase at any depth.

A lot of chess programmers still use a recursive search because they've copied it out of a textbook or from someone else's program. If they would take the time to learn about the alternative of no recursion, then they just might a more elegant -- and possibly faster -- program.

I have not used a goto or the like in at least thirty years. There has never been any need.
There is no need for switch statements or while loops either and for that matter most of the language. They say most programmers use only a subset of the C language anyway so you are not alone.

I wrote a checkers program for the palm a while back and avoided recursion because the operating system requires that applications always maintain their running state on the fly and be capable of taking up where they left off. It was simple to do but I see no elegance whatsoever in switch statements. A switch statement is like admitting that you live in the real world and there is no elegant solution to something and you are reduced to a series of linear tests.

In my view switch is really ugly - but the alternative is uglier. How do you see a big switch as more elegant than recursion? I guess beauty is in the eye of the beholder.
Capital punishment would be more effective as a preventive measure if it were administered prior to the crime.
User avatar
lucasart
Posts: 3232
Joined: Mon May 31, 2010 1:29 pm
Full name: lucasart

Re: Some statistics about promotions and underpromotions.

Post by lucasart »

sje wrote:Symbolic's search has no recursion. There is the one routine Node() which has a big switch statement with each case being a different phase. The routine's main loop hits the switch each time through until the current phase is PhaseExit. At the top of the loop is is single check of a volatile boolean which, if triggered, sets the phase to PhaseExit. There is no unwinding as there is nothing to unwind. There is nothing hidden on the stack to deconstruct as there is no recursion. The search can be paused, and it can also be stopped and restarted at any phase at any depth.

A lot of chess programmers still use a recursive search because they've copied it out of a textbook or from someone else's program. If they would take the time to learn about the alternative of no recursion, then they just might a more elegant -- and possibly faster -- program.
So you use an iterative search, everything is done in one really big function, with a huge switch block. That means you have to handle the stack manually, and create your own stack (for alpha, beta, node_type, pv pointer, ply, etc.). How exactly is that better than a recursive search ?

And writing an iterative search while forcing yourself not to use goto and break or continue, is completely ridiculous. I can only imagine that your Node() function is an enormous pile of knots, with an extremely compolex control flow. For example, when I want to dive into the search (child node) recursively... Oh no wait! Recursion is forbiden, so I set the stack for the next ply manually, but then I cannot use goto, so I need to set a flag to tell all that mess of control structures to branch to the right point and search again the child node. How is that more readable than a neat recursive call ?

IMO an iterative search should use goto. That being said, I do not see the point of using an iterative search. When I think of alpha beta algorithm, I think of it recursively. I do not want to twist my brain into thinking how to "iterativize" something that is naturally recursive. It does not simplify code (quite the opposite) and it does not simplify readability because it makes the control flow much more complex, and forces the reader to think in counterintuitive way about the search.

Again you have decided not to use recursion, not to use goto, setjmp(), longjmp(), break or return in certain places only, etc. But behind these decisions there is only dogma, and no valid technical reason.

As for switch, I do not like the switch statement, and rarely use it. If I know that the compiler will generate a jump table, and the cost of branching is indeed critical to the overall execution time (very rare), then I will use it. Otherwise I often find if's more readable, and when you have long list of cases, you should redesign your code so that the need for switch is not necessary instead IMO (break functions into smaller ones for eg.)
Theory and practice sometimes clash. And when that happens, theory loses. Every single time.
Gerd Isenberg
Posts: 2250
Joined: Wed Mar 08, 2006 8:47 pm
Location: Hattingen, Germany

Re: Some statistics about promotions and underpromotions.

Post by Gerd Isenberg »

sje wrote:A goto is ugly. A setjmp() is uglier. Even continue is bad. There are absolute standards which do not depend on the skill of a coder.
Too dogmatic for my taste - Dijkstra versus Knuth and Torvalds. I find it ugly if you introduce boolean variables only to avoid gotos, breaks or continues.

some links:
http://en.wikipedia.org/wiki/Goto
http://en.wikipedia.org/wiki/Considered_harmful
http://www.codinghorror.com/blog/2007/1 ... l-too.html
http://stevemcconnell.com/ccgoto.htm
User avatar
sje
Posts: 4675
Joined: Mon Mar 13, 2006 7:43 pm

Bull

Post by sje »

Blah, blah, blah.

Enough with the hand-waving. Here's an example of a non-recursive search.

https://dl.dropboxusercontent.com/u/316 ... kieCat.pas

See line 11839, the start of SpookyFindMove. The node processing switch statement (actually a case statement in Pascal) starts at line 12042.

Where is enormous pile of knots?

Where is the extremely complex control flow?

Where is the mess of control structures?
User avatar
Don
Posts: 5106
Joined: Tue Apr 29, 2008 4:27 pm

Re: Some statistics about promotions and underpromotions.

Post by Don »

Gerd Isenberg wrote:
sje wrote:A goto is ugly. A setjmp() is uglier. Even continue is bad. There are absolute standards which do not depend on the skill of a coder.
Too dogmatic for my taste - Dijkstra versus Knuth and Torvalds. I find it ugly if you introduce boolean variables only to avoid gotos, breaks or continues.

some links:
http://en.wikipedia.org/wiki/Goto
http://en.wikipedia.org/wiki/Considered_harmful
http://www.codinghorror.com/blog/2007/1 ... l-too.html
http://stevemcconnell.com/ccgoto.htm
In particular the last article you referenced seems to be well thought out and balanced:

http://stevemcconnell.com/ccgoto.htm
Capital punishment would be more effective as a preventive measure if it were administered prior to the crime.
mcostalba
Posts: 2684
Joined: Sat Jun 14, 2008 9:17 pm

Re: Some statistics about promotions and underpromotions.

Post by mcostalba »

The amazing thing is that after 45 (!) years:

http://www.u.arizona.edu/~rubinson/copy ... rmful.html

People is _still_ discussing about this. It reminds me of the discussions of old people at the pubs that still dispute if the trainer took the right decision to change that soccer forwarded for the other one on a match of the '64 or something...and I, saw with my eyes, they can even get very nervous while discussing about this :-)
AlvaroBegue
Posts: 931
Joined: Tue Mar 09, 2010 3:46 pm
Location: New York
Full name: Álvaro Begué (RuyDos)

Re: Some statistics about promotions and underpromotions.

Post by AlvaroBegue »

I don't follow any of the rules that Steven Edwards advocates. I try to write code in the way that it best expresses my intent, and that often involves using continue, break, multiple returns and rarely (but not never) even goto.
Don wrote:I don't believe in absolutes but it's a very good rule of thumb to avoid multiple returns. One exit point only is almost always a good policy for code readability.
Even this one I don't agree with. If I get to the point in my function where I know what I need to return, an early return statement is the cleanest way to express that.
Sometimes it will happen that you need to do something just before returning from a function and if you have multiple exit points you must code this everywhere you do a return, a lot of code duplication and that is a generally a sign you are doing something wrong.
I have been programming in C++ for a really long time now, and I find that the overwhelming majority of the situations where you need to do something just before returning from a function is best represented by invoking the destructor of some object. In that case, the early return works just fine.

If you are writing C and this is the type of function that is likely to have the need for destructor-type code, sure, it's best to avoid early returns. But then you'll probably end up using a break statement. If you don't do that either, you need to create a boolean variable to decide if you should do another iteration of the loop or not, and that's an ugly hack in my opinion.

Here's some code to illustrate what I am talking about:

Code: Select all

bool is_prime(unsigned n) {
  if (n%2 == 0)
    return n==2;
  for &#40;int k = 3; k*k <= n; k += 2&#41; &#123;
    if &#40;n%k == 0&#41;
      return false;
  &#125;
  return true;
&#125;
mar
Posts: 2559
Joined: Fri Nov 26, 2010 2:00 pm
Location: Czech Republic
Full name: Martin Sedlak

Re: Some statistics about promotions and underpromotions.

Post by mar »

Good, yet another flamewar :)
I personally see nothing wrong about a goto (especially when it saves extra code), I'm not using it that often however (almost never in fact).
I find it insane to not use continue/break.

I prefer

Code: Select all

for (...)
&#123;
    if ( condition_not_met )
        continue;
   do stuff
&#125;
over

Code: Select all

for (...)
&#123;
    if ( condition_met )
    &#123;
       do stuff
    &#125;
&#125;
which creates extra level of nesting, making the code less readable.
To add more oil: I also find exceptions aka supergoto over multiple stack frames absolutely useless, they just suck :)
They add unwinding tables/code (=size overhead) to resulting binary (note that this is only a problem in C++, not in GC-based languages).
Plus wonderful constructs like

Code: Select all

try
&#123;
    do stuff
&#125;
catch&#40; type1 )
&#123;
&#125;
catch&#40; type2 )
&#123;
&#125;
catch&#40; ... )
&#123;
&#125;
instead of

Code: Select all

errcode = do stuff
switch&#40; errcode )
&#123;
    case a&#58;
        ....
    case b&#58;
        ....
    default&#58;
        ....
&#125;
And of course using throw exception instead of return code.
Needless to say it's wonderful that you debug some code and suddenly find yourself somewhere else inside a catch block.
Some people even misuse exceptions to pass return values, which is a very bad practice.
OT: Multiple inheritance also sucks as it's often used to glue completely unrelated classes together (it also makes things a lot more complicated, potentially requiring virtual inheritance).
User avatar
Don
Posts: 5106
Joined: Tue Apr 29, 2008 4:27 pm

Re: Some statistics about promotions and underpromotions.

Post by Don »

AlvaroBegue wrote:I don't follow any of the rules that Steven Edwards advocates. I try to write code in the way that it best expresses my intent, and that often involves using continue, break, multiple returns and rarely (but not never) even goto.
Don wrote:I don't believe in absolutes but it's a very good rule of thumb to avoid multiple returns. One exit point only is almost always a good policy for code readability.
Even this one I don't agree with. If I get to the point in my function where I know what I need to return, an early return statement is the cleanest way to express that.
Note that I am speaking from a C background so your next statement doesn't apply. 9 times out of 10 this comes under the same category as good use of continue and break but my own experience has followed this cycle too often:

1. several returns are coded because it is easier to code.
2. discovery that I need some sort of common "finish-up" code.
3. a single bug as a result that has to be fixed in several places.
4. OR a syntax bug in just one of those places that has to be tracked down.

A common use example of this is when debugging. I will sometime insert a board display call with some information on exit that has to do with the current state at exit time. I have to go in and make that change in several places. Then I take it out which increase the chance of doing this with additional bugs. If this usage example causes a problem then to me it means I'm taking a chance when doing this. Having said that, I do not follow my own advice but will have multiple return statements especially when I feel there is little chance of this happening.

It's a real problem because when reading the same code weeks or months later, the multiple returns quite often turn into "gotcha's", it is really nice to know that there is only one way out of a routine. I find myself using my editor a lot to search for "return" in the code instead of just going to the end of the routine - so that tells me a LOT.

Nevertheless, each person has his own coding style and there may be other things I do that exacerbate this problem that you don't do. That is why there is wisdom in not making rules, let each person make their own rules but not impose them on others.
Sometimes it will happen that you need to do something just before returning from a function and if you have multiple exit points you must code this everywhere you do a return, a lot of code duplication and that is a generally a sign you are doing something wrong.
I have been programming in C++ for a really long time now, and I find that the overwhelming majority of the situations where you need to do something just before returning from a function is best represented by invoking the destructor of some object. In that case, the early return works just fine.

If you are writing C and this is the type of function that is likely to have the need for destructor-type code, sure, it's best to avoid early returns. But then you'll probably end up using a break statement. If you don't do that either, you need to create a boolean variable to decide if you should do another iteration of the loop or not, and that's an ugly hack in my opinion.

Here's some code to illustrate what I am talking about:

Code: Select all

bool is_prime&#40;unsigned n&#41; &#123;
  if &#40;n%2 == 0&#41;
    return n==2;
  for &#40;int k = 3; k*k <= n; k += 2&#41; &#123;
    if &#40;n%k == 0&#41;
      return false;
  &#125;
  return true;
&#125;

Another word about continue and break. I really hate my code to have very many nested compound statements. It gets very confusing after a while. I find it MUCH more readable to test and continue or test and break under some situations if the alternative is yet another level of indentation and nest when there are already many or if the alternative is to have a 200+ character set of tests combined with '&&' and '||' some of which are protected by parenthesis and make you go crossed-eyed trying to figure out what it means. For those who abhor continue, please don't try to tell me that is more readable or likley to be less buggy.
Capital punishment would be more effective as a preventive measure if it were administered prior to the crime.