www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - goto

reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
I was coding a simple Euclidean distance function with limit:

double euclideanDistance(Range)(Range a, Range b, double limit)
{
     limit *= limit;
     double result = 0;
     for (; !a.empty; a.next, b.next)
     {
         enforce(!b.empty);
         auto t = a.head - b.head;
         result += t * t;
         if (result >= limit) goto thatsit;
     }
     enforce(b.empty);
   thatsit:
     return sqrt(result);
}

How would an elegant goto-less approach look like? It should not 
duplicate code, e.g. the call to sqrt.


Andrei
Feb 05 2009
next sibling parent Brad Roberts <braddr puremagic.com> writes:
Andrei Alexandrescu wrote:
 I was coding a simple Euclidean distance function with limit:
 
 double euclideanDistance(Range)(Range a, Range b, double limit)
 {
     limit *= limit;
     double result = 0;
     for (; !a.empty; a.next, b.next)
     {
         enforce(!b.empty);
         auto t = a.head - b.head;
         result += t * t;
         if (result >= limit) goto thatsit;
     }
     enforce(b.empty);
   thatsit:
     return sqrt(result);
 }
 
 How would an elegant goto-less approach look like? It should not
 duplicate code, e.g. the call to sqrt.
 
 
 Andrei
How about:
 double euclideanDistance(Range)(Range a, Range b, double limit)
{ limit *= limit; double result = 0; for (; !a.empty; a.next, b.next) { enforce(!b.empty); auto t = a.head - b.head; result += t * t; if (result >= limit) { b.clear; break; } } enforce(b.empty); return sqrt(result); }
Feb 05 2009
prev sibling next sibling parent reply BCS <none anon.com> writes:
Hello Andrei,

 I was coding a simple Euclidean distance function with limit:
 
 double euclideanDistance(Range)(Range a, Range b, double limit)
 {
 limit *= limit;
 double result = 0;
 for (; !a.empty; a.next, b.next)
 {
 enforce(!b.empty);
 auto t = a.head - b.head;
 result += t * t;
 if (result >= limit) goto thatsit;
 }
 enforce(b.empty);
 thatsit:
 return sqrt(result);
 }
 How would an elegant goto-less approach look like? It should not
 duplicate code, e.g. the call to sqrt.
 
 Andrei
 
I think this is a good reason for more scope(*) versions you could fake it with
 for (; !a.empty; a.next || (enforce(b.empty), false), b.next)
Feb 05 2009
parent reply Robert Fraser <fraserofthenight gmail.com> writes:
BCS wrote:
 Hello Andrei,
 
 I was coding a simple Euclidean distance function with limit:

 double euclideanDistance(Range)(Range a, Range b, double limit)
 {
 limit *= limit;
 double result = 0;
 for (; !a.empty; a.next, b.next)
 {
 enforce(!b.empty);
 auto t = a.head - b.head;
 result += t * t;
 if (result >= limit) goto thatsit;
 }
 enforce(b.empty);
 thatsit:
 return sqrt(result);
 }
 How would an elegant goto-less approach look like? It should not
 duplicate code, e.g. the call to sqrt.

 Andrei
I think this is a good reason for more scope(*) versions you could fake it with
 for (; !a.empty; a.next || (enforce(b.empty), false), b.next)
Which looks even worse. IMO, this is the perfect place for goto -- small function, used only for an exit condition. There's no "spaghetti code" here at all. I know goto used to be abused back in the day, but it has its place.
Feb 05 2009
parent reply Brad Roberts <braddr puremagic.com> writes:
Robert Fraser wrote:
 Which looks even worse. IMO, this is the perfect place for goto -- small
 function, used only for an exit condition. There's no "spaghetti code"
 here at all. I know goto used to be abused back in the day, but it has
 its place.
Oh, I agree. I didn't say that in my response because he specifically asked for other ways to write it. In this case, I see no reason to change it. That said, it can be nearly as clean without the goto for those that are religious about it. Later, Brad
Feb 05 2009
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Brad Roberts wrote:
 Robert Fraser wrote:
 Which looks even worse. IMO, this is the perfect place for goto -- small
 function, used only for an exit condition. There's no "spaghetti code"
 here at all. I know goto used to be abused back in the day, but it has
 its place.
Oh, I agree. I didn't say that in my response because he specifically asked for other ways to write it. In this case, I see no reason to change it. That said, it can be nearly as clean without the goto for those that are religious about it.
Yah, same here. I seem to finally have found one of the elusive cases when goto simplifies things. About Brad's variant - ranges don't define clear, but assigning b = b.init does the trick. (I personally still find the goto version marginally clearer. It's also marginally more efficient because it doesn't do one assignment and one vacuous check. Also the joke with the programmer who throws the water and then applies the known procedure to make coffee comes to mind.) Andrei
Feb 05 2009
parent reply Chris R Miller <lordsauronthegreat gmail.com> writes:
Andrei Alexandrescu wrote:
 Yah, same here. I seem to finally have found one of the elusive cases
 when goto simplifies things.

 About Brad's variant - ranges don't define clear, but assigning b =
 b.init does the trick. (I personally still find the goto version
 marginally clearer. It's also marginally more efficient because it
 doesn't do one assignment and one vacuous check. Also the joke with the
 programmer who throws the water and then applies the known procedure to
 make coffee comes to mind.)
Enlighten those of us unfamiliar with this joke?
Feb 05 2009
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Chris R Miller wrote:
 Andrei Alexandrescu wrote:
 Yah, same here. I seem to finally have found one of the elusive cases
 when goto simplifies things.

 About Brad's variant - ranges don't define clear, but assigning b =
 b.init does the trick. (I personally still find the goto version
 marginally clearer. It's also marginally more efficient because it
 doesn't do one assignment and one vacuous check. Also the joke with the
 programmer who throws the water and then applies the known procedure to
 make coffee comes to mind.)
Enlighten those of us unfamiliar with this joke?
I found a variant of it on http://www.xs4all.nl/~jcdverha/scijokes/6.html: There were two men trying to decide what to do for a living. They went to see a counselor, and he decided that they had good problem solving skills. He tried a test to narrow the area of specialty. He put each man in a room with a stove, a table, and a pot of water on the table. He said "Boil the water". Both men moved the pot from the table to the stove and turned on the burner to boil the water. Next, he put them into a room with a stove, a table, and a pot of water on the floor. Again, he said "Boil the water". The first man put the pot on the stove and turned on the burner. The counselor told him to be an Engineer, because he could solve each problem individually. The second man moved the pot from the floor to the table, and then moved the pot from the table to the stove and turned on the burner. The counselor told him to be a mathematician because he reduced the problem to a previously solved problem. Andrei
Feb 05 2009
parent Bill Baxter <wbaxter gmail.com> writes:
On Fri, Feb 6, 2009 at 2:27 PM, Andrei Alexandrescu
<SeeWebsiteForEmail erdani.org> wrote:

 He tried a test to narrow the area of specialty.  He put each man in a
 room with a stove, a table, and a pot of water on the table.  He said
 "Boil the water".  Both men moved the pot from the table to the stove
 and turned on the burner to boil the water.  Next, he put them into a
 room with a stove, a table, and a pot of water on the floor.  Again,
 he said "Boil the water".  The first man put the pot on the stove and
 turned on the burner.  The counselor told him to be an Engineer,
 because he could solve each problem individually.  The second man
 moved the pot from the floor to the table, and then moved the pot from
 the table to the stove and turned on the burner.  The counselor told
 him to be a mathematician because he reduced the problem to a
 previously solved problem.
The math guy should just stop after putting the pot on the table, then when asked by the counselor why he stopped, then the math guy should refer him to his previous work. --bb
Feb 05 2009
prev sibling next sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
Andrei Alexandrescu wrote:
 I was coding a simple Euclidean distance function with limit:
 
 double euclideanDistance(Range)(Range a, Range b, double limit)
 {
     limit *= limit;
     double result = 0;
     for (; !a.empty; a.next, b.next)
     {
         enforce(!b.empty);
         auto t = a.head - b.head;
         result += t * t;
         if (result >= limit) goto thatsit;
     }
     enforce(b.empty);
   thatsit:
     return sqrt(result);
 }
 
 How would an elegant goto-less approach look like? It should not 
 duplicate code, e.g. the call to sqrt.
 
 
 Andrei
double euclideanDistance(Range)(Range a, Range b, double limit) { limit *= limit; double result = 0; for (; 1; a.next, b.next) { if (a.empty) { enforce(b.empty); break; } enforce(!b.empty); auto t = a.head - b.head; result += t * t; if (result >= limit) break; } return sqrt(result); }
Feb 05 2009
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Walter Bright wrote:
 double euclideanDistance(Range)(Range a, Range b, double limit)
 {
     limit *= limit;
     double result = 0;
     for (; 1; a.next, b.next)
     {
         if (a.empty)
         {
            enforce(b.empty);
            break;
         }
         enforce(!b.empty);
         auto t = a.head - b.head;
         result += t * t;
         if (result >= limit) break;
     }
     return sqrt(result);
 }
Gotta give it to The Man! So after all I couldn't find a good use for goto. Andrei
Feb 05 2009
next sibling parent reply Bill Baxter <wbaxter gmail.com> writes:
On Fri, Feb 6, 2009 at 2:30 PM, Andrei Alexandrescu
<SeeWebsiteForEmail erdani.org> wrote:
 Walter Bright wrote:
 double euclideanDistance(Range)(Range a, Range b, double limit)
 {
    limit *= limit;
    double result = 0;
    for (; 1; a.next, b.next)
    {
        if (a.empty)
        {
           enforce(b.empty);
           break;
        }
        enforce(!b.empty);
        auto t = a.head - b.head;
        result += t * t;
        if (result >= limit) break;
    }
    return sqrt(result);
 }
Gotta give it to The Man! So after all I couldn't find a good use for goto.
Meh. I dislike seeing things like for(; 1; ) or while(true) in a loop (unless it's something like a top level message processing loop or such). At least in your goto version I know from a glance at the for() part that at most we're going to iterate till the thing is empty. --bb
Feb 05 2009
parent Chris R Miller <lordsauronthegreat gmail.com> writes:
Bill Baxter wrote:
 On Fri, Feb 6, 2009 at 2:30 PM, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org>  wrote:
 Walter Bright wrote:
 double euclideanDistance(Range)(Range a, Range b, double limit)
 {
     limit *= limit;
     double result = 0;
     for (; 1; a.next, b.next)
     {
         if (a.empty)
         {
            enforce(b.empty);
            break;
         }
         enforce(!b.empty);
         auto t = a.head - b.head;
         result += t * t;
         if (result>= limit) break;
     }
     return sqrt(result);
 }
Gotta give it to The Man! So after all I couldn't find a good use for goto.
Meh. I dislike seeing things like for(; 1; ) or while(true) in a loop (unless it's something like a top level message processing loop or such). At least in your goto version I know from a glance at the for() part that at most we're going to iterate till the thing is empty.
Wherever did the foreach(auto foo in bar) feature request go? Or did that conflict with existing syntax?
Feb 06 2009
prev sibling parent reply Don <nospam nospam.com> writes:
Andrei Alexandrescu wrote:
 Walter Bright wrote:
 double euclideanDistance(Range)(Range a, Range b, double limit)
 {
     limit *= limit;
     double result = 0;
     for (; 1; a.next, b.next)
     {
         if (a.empty)
         {
            enforce(b.empty);
            break;
         }
         enforce(!b.empty);
         auto t = a.head - b.head;
         result += t * t;
         if (result >= limit) break;
     }
     return sqrt(result);
 }
Gotta give it to The Man! So after all I couldn't find a good use for goto. Andrei
The irony is that's Walter's the biggest goto advocate I know, other than Linus Torvalds.
Feb 06 2009
parent reply Walter Bright <newshound1 digitalmars.com> writes:
Don wrote:
 The irony is that's Walter's the biggest goto advocate I know, other 
 than Linus Torvalds.
I don't mind being compared to Linus <g>.
Feb 06 2009
parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
"Walter Bright"  wrote
 Don wrote:
 The irony is that's Walter's the biggest goto advocate I know, other than 
 Linus Torvalds.
I don't mind being compared to Linus <g>.
If you like, I can name several not-so-spectacular coders that I know who like to use goto ;) -Steve
Feb 09 2009
prev sibling next sibling parent Derek Parnell <derek psych.ward> writes:
On Thu, 05 Feb 2009 19:37:35 -0800, Andrei Alexandrescu wrote:

 I was coding a simple Euclidean distance function with limit:
 
 double euclideanDistance(Range)(Range a, Range b, double limit)
 {
      limit *= limit;
      double result = 0;
      for (; !a.empty; a.next, b.next)
      {
          enforce(!b.empty);
          auto t = a.head - b.head;
          result += t * t;
          if (result >= limit) goto thatsit;
      }
      enforce(b.empty);
    thatsit:
      return sqrt(result);
 }
 
 How would an elegant goto-less approach look like? It should not 
 duplicate code, e.g. the call to sqrt.
I'm not sure about the elegant part but ... double euclideanDistance(Range)(Range a, Range b, double limit) { limit *= limit; double result = 0; do { -- Precondition for next iteration; 'a' ought not be empty. if (a.empty) { -- If it is empty then 'b' must also be empty. enforce(b.empty); -- No more work needs be done. break; } -- If 'a' isn't empty then 'b' must not be empty. enforce(!b.empty); -- Perform this iteration's work. auto t = a.head - b.head; result += t * t; -- If the limit has been reached then stop working. if (result >= limit) break; -- Move along to the next element pair. a.next; b.next; -- And repeat. } while (true); return sqrt(result); } -- Derek Parnell Melbourne, Australia skype: derek.j.parnell
Feb 05 2009
prev sibling next sibling parent "Lionello Lunesu" <lionello lunesu.remove.com> writes:
"Andrei Alexandrescu" <SeeWebsiteForEmail erdani.org> wrote in message 
news:gmgb9u$qkg$1 digitalmars.com...
I was coding a simple Euclidean distance function with limit:

 double euclideanDistance(Range)(Range a, Range b, double limit)
 {
     limit *= limit;
     double result = 0;
     for (; !a.empty; a.next, b.next)
     {
         enforce(!b.empty);
         auto t = a.head - b.head;
         result += t * t;
         if (result >= limit) goto thatsit;
     }
     enforce(b.empty);
   thatsit:
     return sqrt(result);
 }

 How would an elegant goto-less approach look like? It should not duplicate 
 code, e.g. the call to sqrt.
I would refactor the a/b.next and a/b.empty into a new range that does the enforcing and then you can use break. L.
Feb 05 2009
prev sibling next sibling parent reply Daniel Keep <daniel.keep.lists gmail.com> writes:
Andrei Alexandrescu wrote:
 I was coding a simple Euclidean distance function with limit:
 
 double euclideanDistance(Range)(Range a, Range b, double limit)
 {
     limit *= limit;
     double result = 0;
     for (; !a.empty; a.next, b.next)
     {
         enforce(!b.empty);
         auto t = a.head - b.head;
         result += t * t;
         if (result >= limit) goto thatsit;
     }
     enforce(b.empty);
   thatsit:
     return sqrt(result);
 }
 
 How would an elegant goto-less approach look like? It should not
 duplicate code, e.g. the call to sqrt.
 
 
 Andrei
The goto approach looks a bit messy because it isn't immediately clear what the relationship between a and b's lengths are. Personally, I'd do it like this: double euclideanDistance(Range)(Range as, Range bs, double limit) { limit *= limit; double result = 0; foreach( ab ; zip(as, bs, ZipStyle.EnforceLength) ) { auto t = ab._0.head - ab._1.head; result += t * t; if (result >= limit) break; } return sqrt(result); } Of course, if we had foreach support for tuple unpacking... double euclideanDistance(Range)(Range as, Range bs, double limit) { limit *= limit; double result = 0; foreach( a, b ; zip(as, bs, ZipStyle.EnforceLength) ) { auto t = a.head - b.head; result += t * t; if (result >= limit) break; } return sqrt(result); } :D -- Daniel
Feb 05 2009
next sibling parent "Lionello Lunesu" <lionello lunesu.remove.com> writes:
My hero! ;)
Feb 06 2009
prev sibling parent bearophile <bearophileHUGS lycos.com> writes:
Daniel Keep:

 Of course, if we had foreach support for tuple unpacking...
 
 double euclideanDistance(Range)(Range as, Range bs, double limit)
 {
     limit *= limit;
     double result = 0;
     foreach( a, b ; zip(as, bs, ZipStyle.EnforceLength) )
     {
         auto t = a.head - b.head;
         result += t * t;
         if (result >= limit) break;
     }
     return sqrt(result);
 }
That's closer to the way code is meant to be written :-) Few other details: auto t = a.head - b.head; result += t * t; May become: result += (a.head - b.head) ** 2; This isn's nice looking (you also may want to zip many iterables): zip(as, bs, ZipStyle.EnforceLength) How many zip behaviours are useful? Among the possible ones there are: 1) stop as soon as the shorter iterable ends; 2) stop when the longest iterable ends, yielding item.init items to fill blanks. 3) assert that they are all of the same length, as you ask for. A simpler solution is to make zip support only (1), avoid ugly constants. To support (2) you it can be invented an iterable wrapper that yields the constant you want when the given iterable ends, for example: xzip(iter1, xextend(iter2, 0.0)) And regarding (3) I don't have many ideas. But why the original code by Alex has those enforce() to be sure the iterables have the same length? Maybe the best thing is just to not enforce that. So this may be a readable version (no .heads): double limitedEuclideanDistance(Range)(Range iter2, Range iter2, double limit) { limit = limit ** 2; double sqr_dist = 0.0; foreach (x1, x2 in xzip(iter1, iter2)) { sqr_dist += (x1 - x2) ** 2; if (sqr_dist >= limit) break; } return sqrt(sqr_dist); } Bye, bearophile
Feb 06 2009
prev sibling next sibling parent "Nick Sabalausky" <a a.a> writes:
"Andrei Alexandrescu" <SeeWebsiteForEmail erdani.org> wrote in message 
news:gmgb9u$qkg$1 digitalmars.com...
I was coding a simple Euclidean distance function with limit:

 double euclideanDistance(Range)(Range a, Range b, double limit)
 {
     limit *= limit;
     double result = 0;
     for (; !a.empty; a.next, b.next)
     {
         enforce(!b.empty);
         auto t = a.head - b.head;
         result += t * t;
         if (result >= limit) goto thatsit;
     }
     enforce(b.empty);
   thatsit:
     return sqrt(result);
 }

 How would an elegant goto-less approach look like? It should not duplicate 
 code, e.g. the call to sqrt.
I haven't looked at any of the replies yet, and euclidean distance and Ranges are things I'd have to look up (I haven't actually had a chance to look at the Range docs), but I would do something like this: double euclideanDistance(Range)(Range a, Range b, double limit) { limit *= limit; double result = 0; bool foundIt=false; for (; !a.empty && !foundIt; a.next, b.next) { enforce(!b.empty); auto t = a.head - b.head; result += t * t; if (result >= limit) { foundIt = true; break; // This line needed? } } if(!foundIt) // This line needed? enforce(b.empty); return sqrt(result); }
Feb 05 2009
prev sibling next sibling parent "Christof Schardt" <csnews christof-schardt.de> writes:
In the web-source of hius adventure-game
http://www-cs-staff.stanford.edu/~uno/programs/advent.w.gz
Knuth comments (resp. warns the reader):

"By the way, if you don't like |goto| statements, don't read this. (And 
don't
read any other programs that simulate multistate systems.)"
Don Knuth, September 1998

This may be dated. But while I cannot judge  the reasoning,
I did not want to miss to post it here. At least for its subtle humor.

Christof
Feb 05 2009
prev sibling parent grauzone <none example.net> writes:
I'd prefer to have some kind of goto, which enforces structured 
programming. Something like:

double euclideanDistance(Range)(Range a, Range b, double limit)
{
     limit *= limit;
     double result = 0;
     foo: {
         for (; !a.empty; a.next, b.next)
         {
             enforce(!b.empty);
             auto t = a.head - b.head;
             result += t * t;
             if (result >= limit) break foo;
         }
         enforce(b.empty);
     }
     return sqrt(result);
}
Feb 05 2009