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

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.
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 »

Don wrote:
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
Yes, that's a very good article on the subjects.

I think that logical complexity, and deep nesting level is very important, and a problem often minimized or overlooked by anti-goto djihadists.

I use a goto in an unusual place in my code. It doesn't fall into the categories of accepted goto use, so it's an heresy in some sense. But when it's right, you just know it, regardless of the "rules"...

I have a function that plays a legal move on the board. It's already complex and deeply nested, and then I add null move in the search so I need to handle those. I could do a different function to play a null move, but that's not an acceptable solution because they would share a bunch of code (change turn of play and xor it in the zobrist among many other things). This shared code is especially non trivial and it's easy to screw it, so duplicating it is a recipie for disaster. So it all has to be in the same function.

But handling the null move would mean add extra nesting and make the function less readable like so:

Code: Select all

if &#40;move != null_move&#41; &#123;
    // play a legal move
&#125;
// finish section
That's ok on a trivial example, but imagine that "play a legal move" occupies several screen pages and is deeply nested already...

Instead I opted for

Code: Select all

if &#40;move == null_move&#41; goto finish;

// play a legal move

finish&#58;
It reduces nesting level, and makes the code clearer. the way I think of the code is as follows: function should be read with legal move in mind, and the null move is a trivial case where there's nothing to do in the "play a move" section. So you shouldn't penalized the general case in terms of legibility because of this trivial case.

Some people may disagree with that though. Beauty is in the eye of the beholder as you said.

But in reality, the enemy is neither goto, setjmp, longjmp, break, continue, etc. The enemy is complexity which correlates with bugs and with hard to maintain code. An abuse of goto leads to complexity, but so does an abuse of control structures (example of deeply nested ifs which are *much worse* than a goto).

In the purest sense, if's are bad, loops are bad, variables (i/o constants) are bad. If you look at code written in functional languages like CAML or Haskell, it gives you an idea of how to remove possiblity of bugs and make code *provably correct* by using recursions everywhere. It's not efficient like C, but in cases where the algorithms are highly complex and bugs cannot be tolerated, it may be the right choice.

The various keywoprds of the language are just what they are. They are neither bad nor good, it all depends how we use them.

So the only dogma we can all agree to isthat bad code is bad (and bad code can be written with or without goto...)
Theory and practice sometimes clash. And when that happens, theory loses. Every single time.
syzygy
Posts: 5566
Joined: Tue Feb 28, 2012 11:56 pm

Re: Some statistics about promotions and underpromotions.

Post by syzygy »

mcostalba wrote: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 :-)
I think the problem is that people are interpreting Dijkstra's paper outside its proper context. He was just making the point that "unbridled use of the go to statement" leads to hard to understand code at a time when people had not grown up with the idea of structured programming. Nowadays this is telling nothing new at all, so instead some people turn to a dogmatic religious view of Dijkstra's paper.

Steven is going even further than that: he wants no go to statement, no recursion, no break, no continue, and a single exit point. Five things that mutually bite each other. The result can only be an explosion of nesting level and boolean variables.

I just found Knuth's paper on go to.
Knuth wrote:I believe that by presenting such a view I am not in fact disagreeing sharply with Dijkstra's ideas, since he recently wrote the following: "Please don't fall into the trap of believing that I am terribly dogmatical about [the go to statement]. I have the uncomfortable feeling that others are making a religion out of it, as if the conceptual problems of programming could be solved by a single trick, by a simple form of coding discipline!". In other words, it seems that fanatical advocates of the New Programming are going overboard in their strict enforcement of morality and purity in programs.
So maybe next time someone indicates that Fortran is a useful tool for him that gets his job done, let's not immediately take over the thread by praying to god to save his soul.
User avatar
Don
Posts: 5106
Joined: Tue Apr 29, 2008 4:27 pm

Re: Some statistics about promotions and underpromotions.

Post by Don »

syzygy wrote:
mcostalba wrote: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 :-)
I think the problem is that people are interpreting Dijkstra's paper outside its proper context. He was just making the point that "unbridled use of the go to statement" leads to hard to understand code at a time when people had not grown up with the idea of structured programming. Nowadays this is telling nothing new at all, so instead some people turn to a dogmatic religious view of Dijkstra's paper.

Steven is going even further than that: he wants no go to statement, no recursion, no break, no continue, and a single exit point. Five things that mutually bite each other. The result can only be an explosion of nesting level and boolean variables.

I just found Knuth's paper on go to.
Knuth wrote:I believe that by presenting such a view I am not in fact disagreeing sharply with Dijkstra's ideas, since he recently wrote the following: "Please don't fall into the trap of believing that I am terribly dogmatical about [the go to statement]. I have the uncomfortable feeling that others are making a religion out of it, as if the conceptual problems of programming could be solved by a single trick, by a simple form of coding discipline!". In other words, it seems that fanatical advocates of the New Programming are going overboard in their strict enforcement of morality and purity in programs.
So maybe next time someone indicates that Fortran is a useful tool for him that gets his job done, let's not immediately take over the thread by praying to god to save his soul.
Probably most of us enjoy writing software to one extent or another but some people are more into the "processes" or the craft of doing it than others. For me, even though I do enjoy it, I see it as an obstacle in standing between me and the thing I want to build. I think for Steven it is the building itself that is the fun part. I'm definitely not above an ugly hack to get the job done and that has bit me many times. I don't believe goto, break and continue is an ugly hack but perhaps to someone like Steven it is. It's his "rock and roll" and to some people if it isn't rock and roll it isn't music.

I have noticed over the years that Steven loves structure and process - and you can see that is evident in the awesome work he has done with the chess standards of PGN, FEN, EPD, that we we all use. We owe him a debt of gratitude for these things. I don't think I have ever taken the time to tell him this, so hopefully he is reading it now. Thank you Steven!!
Capital punishment would be more effective as a preventive measure if it were administered prior to the crime.
User avatar
sje
Posts: 4675
Joined: Mon Mar 13, 2006 7:43 pm

Re: Bull

Post by sje »

I am not saying that recursion is bad. Symbolic uses recursion as part of its perft(). But perft() is much different from a regular search as I don't expect a perft() call to be interrupted by a time-out or user intervention. A regular search must be able to stop gracefully with its partial results intact. Throwing an exception or calling longjmp() should be used for a truly exceptional condition, like power failure or processor-on-fire.

A new problem occurs with the introduction of a multithreaded search where the search continues while individual threads must be repeatedly re-run with different data. In addition to the requirement to stop gracefully, there is now the need to share data among the threads. It's tough to do this when a lot of interesting data is hidden on the inaccessible activation frames on different stacks local to each thread. With an old style recursive approach, it can be very hard to pause a thread, save its state, and later resume that thread.

Now, with an non-recursive approach, all of the above problems may be solved without excessive anguish. Also, with the details of a thread's state explicitly available and not hidden, a thread could even be restarted on a different machine with a different architecture as long as the semantics remained constant. Indeed, this is one of my goals with Symbolic; to allow multiple machines on the LAN to contribute to a search in a very integrated, yet portable, manner.

General comment:

I have noted over many years of professional experience that if a shop allows coders to use unstructured techniques, then the result is nearly always crappy code. It is also expensive code, for it much more often needs costly maintenance and modification. Yet this is tolerated because that extra expense may be pushed to the next business quarter. Sadly, this has become the American Way.