[comp.lang.c] Oh nooo!

lewie@pur-ee.UUCP (Jeff Lewis) (09/07/89)

[Dave Jones offers an example of what he thinks is a valid use of goto]:
[code trimmed to get to the meat]

>  while(rule = (Rule*)Queue_iter_next(&rule_iter)) {
>    
>    while(rsym = (Symbol*)Queue_iter_next(&rsym_iter)) {
>	switch (derives(rsym)) {
>	case derives_nothing:
>	  goto next_rule;
>	....
>	}
>    }
>    
>  next_rule: continue;
>    
>  }

I'm sure this comes up often enough, but the reason I'd say there's nothing
wrong with this type of goto is that it is the equivalent of a continue
with a label, i.e.:

while foo (...) {
    while (...) {
	...
	continue foo; 
	...
    }
}
('foo' is a loop label, which can be used within the loop's scope to alter
flow of control via break or continue)

This, I would say, is just as structured as the simple 'break' and 'continue'
that I presume most people have no problem with.  Of course C doesn't offer
this obvious functionality, so you fake it with the occasional 'goto'.  Is
there anything wrong with this?

hascall@atanasoff.cs.iastate.edu (John Hascall) (09/07/89)

In article <12793@pur-ee.UUCP> lewie@ecn-ee.UUCP writes:
}[Dave Jones offers an example of what he thinks is a valid use of goto]:

    [using goto to get out of a nested control structure]

}I'm sure this comes up often enough, but the reason I'd say there's nothing
}wrong with this type of goto is that it is the equivalent of a continue
}with a label, i.e.:
 
}while foo (...) {
}    while (...) {
}	...
}	continue foo; 
}	...
}    }
}}

  I have often wished for something similar, my thoughts have tended toward
  the synatx:

	  continue [constant-integer-expression];
	  break [constant-integer-expression];

   where the [optional] expression indicated how many nested structures
   to continue or break, with the default being 1 (just like the current
   "continue" and "break").

   While we are on the subject of loops, how do people feel about the
   practice of using #define to "extend" the language?  For example:

   #define loop     for (;;)
   #define exitloop break

   loop {
	foo();
	if (bar()) exitloop;
   }

John Hascall

schemers@egrunix.UUCP (Roland Schemers) (09/07/89)

>   While we are on the subject of loops, how do people feel about the
>   practice of using #define to "extend" the language?  For example:
>
>   #define loop     for (;;)
>   #define exitloop break
>
>   loop {
>	foo();
>	if (bar()) exitloop;
>   }
>

I thought about using the same type of #defines, but what happens when
you have the following:

   loop {
	....
	while (x<h) {		// or a for(;;) loop
 	     ...
             ...
	     exitloop;
	}
	....
    }

Wont the exitloop cause the while to break? This construct looks nice,
as long as you remember that you cant have any other loops (while, for, etc)
inside of your loop construct. How about:

#define begin_loop(name) for(;;)
#define end_loop(name)   name:;
#define exit_loop(name)  goto name;

	begin_loop(read_line) {
	...
	if (whatever) exit_loop(read_line);
	...
	} end_loop(read_line)

I haven't tried this, so I don't know if it is syntatically correct.

roland

ps. personally I think redefining the langauge causes more problems then it
is worth. For personel use its fine, but once other programmers have to
start modifing your code, it only leads to problems.

-- 
Roland J. Schemers III                  'Real programmers don't write specs.
Systems Programmer                      Users should be grateful for whatever
Oakland University                      they get. They are lucky to get any
schemers@unix.secs.oakland.edu		programs at all.'

schemers@egrunix.UUCP (Roland Schemers) (09/07/89)

I just compiled this, and it works (gcc 1.35.0):

#define begin_loop(name)	for(;;)
#define exit_loop(name)		goto name;
#define end_loop(name)		name:;

main()
{

	begin_loop(test) {
		printf("hello!\n");
		exit_loop(test);
		printf("goodbye!\n");
	} end_loop(test)

}

It only prints "hello!"

-- 
Roland J. Schemers III                  'Real programmers don't write specs.
Systems Programmer                      Users should be grateful for whatever
Oakland University                      they get. They are lucky to get any
schemers@unix.secs.oakland.edu		programs at all.'

jeenglis@nunki.usc.edu (Joe English) (09/08/89)

In article <1461@atanasoff.cs.iastate.edu> hascall@atanasoff.cs.iastate.edu.UUCP (John Hascall) writes:
>In article <12793@pur-ee.UUCP> lewie@ecn-ee.UUCP writes:
>}[...] the equivalent of a continue with a label, i.e.:
> 
>}while foo (...) {
>}    while (...) {
>}	...
>}	continue foo; 
>}	...
>}    }
>
>  I have often wished for something similar, my thoughts have tended toward
>  the synatx:
>
>	  continue [constant-integer-expression];
>	  break [constant-integer-expression];
>
>   where the [optional] expression indicated how many nested structures
>   to continue or break, with the default being 1 (just like the current
>   "continue" and "break").

Oog... I don't think that's such a good idea; it's
easier to look for a label than to count sets of braces --
and check that they belong to a while/for/do and not an
if.  Plus, if later on you move the code around, adding
or deleting loops, you can introduce errors that aren't
easy to spot.

>   While we are on the subject of loops, how do people feel about the
>   practice of using #define to "extend" the language?  For example:
>
>   #define loop     for (;;)
>   #define exitloop break

I'm against this in general, but I've seen it used
quite effectively in some cases for information hiding:

#define foo_iterate(idx,foo) for (idx=foo.items;idx<foo.lastitem;++idx)
...
       foo_iterate(i,qux) {
            ... use i ...
       }

Whether this makes things clearer or more obfuscated
is debatable.

--Joe English

  jeenglis@nunki.usc.edu

djones@megatest.UUCP (Dave Jones) (09/08/89)

From article <147@egrunix.UUCP>, by schemers@egrunix.UUCP (Roland Schemers):
>>   While we are on the subject of loops, how do people feel about the
>>   practice of using #define to "extend" the language?
>>

I don't like 'em.

I call such things, "SLM"'s, which stands for "silly little macros".
Whether or not a goto is a Good Thing, or a Bad Thing, it is not
improved by hiding it so that some unfortunate code reader has to
track it down inside a macro in some #include file.

djones@megatest.UUCP (Dave Jones) (09/08/89)

From article <1461@atanasoff.cs.iastate.edu>, by hascall@atanasoff.cs.iastate.edu (John Hascall):
...
>   I have often wished for something similar, my thoughts have tended toward
>   the synatx:
> 
> 	  continue [constant-integer-expression];
> 	  break [constant-integer-expression];
> 
>    where the [optional] expression indicated how many nested structures
>    to continue or break, with the default being 1 (just like the current
>    "continue" and "break").
> 

I like named blocks better. If you explicitly say how many levels to
exit, you will have trouble if you add or remove a level during development
or maintenence. Besides, the reader, or even the developer, may
miscount the levels.

At T.I. back in the seventies, I worked on and with
a languages called TIP and MPP, both Pascal variants.
They had this sort of thing:


       loop:
         while expr do
	   loopbody:
              begin

                  ...
		  if finished_with_this_iteration do
                     escape loopbody;

                  ... 

                  if finished_with_loop do
                     escape loop;

              end;

Notice that the "escape loopbody" is equivalent to a continue-statement.

The nested scope rules even allowed you to escape from a parent procedure.
I actually used that feature once to do a sort of "structured longjmp".
That was in a program for controlling an oil platform. No kidding.
Sure hope I did it right.

bill@twwells.com (T. William Wells) (09/08/89)

: while(rule = (Rule*)Queue_iter_next(&rule_iter)) {
:
:   while(rsym = (Symbol*)Queue_iter_next(&rsym_iter)) {
:    switch (derives(rsym)) {
:    case derives_nothing:
:      goto next_rule;
:    ....
:    }
:   }
:
: next_rule: continue;
:
: }

Look Ma, no goto!

	while(rule = (Rule*)Queue_iter_next(&rule_iter)) {
		while(rsym = (Symbol*)Queue_iter_next(&rsym_iter)) {
			switch (derives(rsym)) {
			case derives_nothing:
				break;
			.... (cases that want to loop use continue)
			}
			break;
		}
	}

I use this one all the time. And I do mean all the time. This is an
example of how I write the argument parser for my programs:

	init_program(argv[0]);
	list_ids_only = 0;
	all_users = 0;
	user_name = 0;
	sys_name = 0;
	kill_id = 0;
	interactive_kill = 0;
	show_machines = 0;
	show_procs = 0;
	show_queue = 0;
	no_kill = 0;
	opterr = 0;
	while (1) {
		switch (getopt(argc, argv, "aF:hik:Kmpqr:s:u:x:X")) {
		case EOF:                                       break;
		default:  usage("illegal option or missing option argument");
		case 'a': all_users = 1;                        continue;
		case 'F': set_directory(optarg);                continue;
		case 'h': uustat_help();
		case 'i': list_ids_only = 1;                    continue;
		case 'k': kill_id = optarg; func = my_unlink;   continue;
		case 'K': interactive_kill = 1;                 continue;
		case 'm': show_machines = 1;                    continue;
		case 'p': show_procs = 1;                       continue;
		case 'q': show_queue = 1;                       continue;
		case 'r': kill_id = optarg; func = my_touch;    continue;
		case 's': sys_name = optarg;                    continue;
		case 'u': user_name = optarg;                   continue;
		case 'x': Debug_level = atoi(optarg);           continue;
		case 'X': no_kill = 1;                          continue;
		}
		break;
	}

And here is how I code state machines:

	state = ST_INIT;
	while (1) {
		... get inpot
		switch (state) {
		case ST_INIT:
			... continue for the next state
			... break to exit the state machine
		...
		}
		break;
	}

Yes, I know all the limitations of this method. And yes, I have
already though of all the arguments for why one shouldn't do this. I
compared them with all the problems of using gotos and found this to
be preferable.

After seven years of C programming, I still haven't used a goto.

---
Bill                    { uunet | novavax | ankh | sunvice } !twwells!bill
bill@twwells.com

ray@philmtl.philips.ca (Raymond Dunn) (09/09/89)

In article <1461@atanasoff.cs.iastate.edu> hascall@atanasoff.cs.iastate.edu.UUCP (John Hascall) writes:
 >  I have often wished for something similar, my thoughts have tended toward
 >  the synatx:
 >
 >	  continue [constant-integer-expression];
 >	  break [constant-integer-expression];
 >
 >   where the [optional] expression indicated how many nested structures
 >   to continue or break

Oh nooo! 


-- 
Ray Dunn.                    | UUCP: ..!uunet!philmtl!ray
Philips Electronics Ltd.     | TEL : (514) 744-8200  Ext: 2347
600 Dr Frederik Philips Blvd | FAX : (514) 744-6455
St Laurent. Quebec.  H4M 2S9 | TLX : 05-824090

john@ontek.UUCP (John Stanley) (09/09/89)

In article <12793@pur-ee.UUCP>, lewie@pur-ee.UUCP (Jeff Lewis) writes:
> This, I would say, is just as structured as the simple 'break' and 'continue'
> that I presume most people have no problem with.  Of course C doesn't offer
> this obvious functionality, so you fake it with the occasional 'goto'.  Is
> there anything wrong with this?

Absolutely not.  The main objection to the use of 'goto' is when it is a
substitute for careful design.  It is perfectly possible to use the 'goto'
statement in a structured manner, as you point out.  To reject a useful
language construct purely on the basis of some sort of "purity of code"
fetish is quite foolish.  The point here is to make careful use of what can
be a most unclear construct.  I am sure we have all seen code which does
not have 'goto's which is quite horrible, so merely eschewing this one
feature does not guarantee high quality code.  Conversely, the presence of
a 'goto' in a piece of code does not automatically render it unclean. :-)

The argument against 'goto' was originally (I believe) an argument against
the *indiscriminate* use of it in lieu of other control structures, not
against the 'goto' statement itself.

	  JAS

ts@cup.portal.com (Tim W Smith) (09/09/89)

"break 3" or "continue 5" suck.  Suppose the code with the break or
continue gets moved in or out a level?  You've got to find and change
the numbers.

If the blocks are named, "break spam" or "continue parsing" is immune
to changes of the nesting inside blocks spam and parsing.

						Tim Smith

djones@megatest.UUCP (Dave Jones) (09/10/89)

From article <1989Sep8.070123.4416@twwells.com), by bill@twwells.com (T. William Wells):
) : while(rule = (Rule*)Queue_iter_next(&rule_iter)) {
) :
) :   while(rsym = (Symbol*)Queue_iter_next(&rsym_iter)) {
) :    switch (derives(rsym)) {
) :    case derives_nothing:
) :      goto next_rule;
) :    ....
) :    }
) :   }
) :
) : next_rule: continue;
) :
) : }
) 
) Look Ma, no goto!
) 
) 	while(rule = (Rule*)Queue_iter_next(&rule_iter)) {
) 		while(rsym = (Symbol*)Queue_iter_next(&rsym_iter)) {
) 			switch (derives(rsym)) {
) 			case derives_nothing:
) 				break;
) 			.... (cases that want to loop use continue)
) 			}
) 			break;
) 		}
) 	}
) 

Your mother should know that you removed a goto but added a
fatal bug.  I would prefer the goto.  Ask your Ma.

steve@umigw.MIAMI.EDU (steve emmerson) (09/12/89)

In article <7887@goofy.megatest.UUCP> djones@megatest.UUCP (Dave Jones) 
writes:

>Your mother should know that you removed a goto but added a
>fatal bug.  I would prefer the goto.  Ask your Ma.

Since no one seems to have asked, and I'm curious, I'll bite.

Where's the bug?
-- 
Steve Emmerson                      Inet: steve@umigw.miami.edu [128.116.10.1]
SPAN: miami::emmerson (host 3074::) UUCP: ...!ncar!umigw!steve
"The best lack all conviction, while the worst are full of passionate
intensity" -- Yeats

bill@twwells.com (T. William Wells) (09/12/89)

In article <7887@goofy.megatest.UUCP> djones@megatest.UUCP (Dave Jones) writes:
: From article <1989Sep8.070123.4416@twwells.com), by bill@twwells.com (T. William Wells):
: ) : while(rule = (Rule*)Queue_iter_next(&rule_iter)) {
: ) :   while(rsym = (Symbol*)Queue_iter_next(&rsym_iter)) {
: ) :    switch (derives(rsym)) {
: ) :    case derives_nothing:
: ) :      goto next_rule;
: ) :    ....
: ) :    }
: ) :   }
: ) : next_rule: continue;
: ) : }
: )
: )     while(rule = (Rule*)Queue_iter_next(&rule_iter)) {
: )             while(rsym = (Symbol*)Queue_iter_next(&rsym_iter)) {
: )                     switch (derives(rsym)) {
: )                     case derives_nothing:
: )                             break;
: )                     .... (cases that want to loop use continue)
: )                     }
: )                     break;
: )             }
: )     }
: )
:
:                              you removed a goto but added a
: fatal bug.  I would prefer the goto.

Well yeah, so would I. But what is the bug? I've just reread the code
and don't see where I've broken it. I'm prepared to be red-faced
because this has go to be something really obvious, but what?

---
Bill                    { uunet | novavax | ankh | sunvice } !twwells!bill
bill@twwells.com

djones@megatest.UUCP (Dave Jones) (09/13/89)

From article <1989Sep12.014534.1503@twwells.com), by bill@twwells.com (T. William Wells):
) In article <7887@goofy.megatest.UUCP) djones@megatest.UUCP (Dave Jones) writes:
) : From article <1989Sep8.070123.4416@twwells.com), by bill@twwells.com (T. William Wells):
)))) while(rule = (Rule*)Queue_iter_next(&rule_iter)) {
))))   while(rsym = (Symbol*)Queue_iter_next(&rsym_iter)) {
))))    switch (derives(rsym)) {
))))    case derives_nothing:
))))      goto next_rule;
))))    ....
))))    }
))))   }
)))) next_rule: continue;
)))) }
)))
)))     while(rule = (Rule*)Queue_iter_next(&rule_iter)) {
)))             while(rsym = (Symbol*)Queue_iter_next(&rsym_iter)) {
)))                     switch (derives(rsym)) {
)))                     case derives_nothing:
)))                             break;
)))                     .... (cases that want to loop use continue)
)))                     }
)))                     break;
)))             }
)))     }
)))
) :
) :                              you removed a goto but added a
) : fatal bug.  I would prefer the goto.
) 
) Well yeah, so would I. But what is the bug? I've just reread the code
) and don't see where I've broken it. I'm prepared to be red-faced
) because this has go to be something really obvious, but what?
) 

DON'T PANIC.

Your face is going to be just fine. But it's lucky for me that I don't blush.
You didn't misread it. I did. In fact, I read it half a dozen times before I saw
the "break" at the end of the while-loop.

Boy, that's wierd.

No offense, but you won't catch me using this device. Different strokes,
I guess.

Maybe we should start a debate: "Breaks at end of while-loops... considered
harmful?"  Oh Nooooooooooooooo!!!