[comp.lang.c] Another "D" idea

rk9005@cca.ucsf.edu (Roland McGrath) (03/06/88)

I have yet another idea for "D".  This one is quite a bit tamer than some
of the others I've seen.

How about anonymous structs and unions?
For example:
	struct { toggle:1; };
	union { int i; float f; }
	x() { return(toggle ? i : f); }
Granted, the main use of global anonymous structs is for less-than-a-char
values and anonymous unions look alot like Fortran equivalences (God forbid
that C (or D) should get *anything* for (ugh!) Fortran!!! ;-).
But I think these could be useful.  Anyway, the most useful use of them
would be inside structs and unions.  The only problem is with the syntax,
because
	struct x { int a, b; }
	struct x;
does nothing but define the type.  I suppose we could introduce
an "anonymous" keyword or something, but that seems ugly.
However, assuming we did that, something like
	struct popen_info {
		FILE;
		int pid, status;
	};
could be interesting.  Then popen could return a (FILE *)(struct popen_info),
including whatever was needed for file i/o in the FILE part and the pid
of the child in the rest; and when pclose got this thing, it could pass
a (FILE *) (struct popen_info) to fclose and fclose would never know the
difference.

Now this may be a bad example (I can find some serious problems with it
myself), but I think it might be a good idea.  The main problem is the
syntax of anonymous tagged structs.


On the switch/fallthrough discussion, I think the best solution is
to have two statements, switch and select (or something), each with
different default behavior.  gotos to case labels are also a good idea.
(And "goto default".)  A Cish language developed around here has these
things (although I think it's got "select" being the semantics of the
present "switch" statement, which I think is wrong); it's also got
things like "break 2;" (e.g.,
	while (x > 0) { while (y != -1) { if (a) break 2; } }
), which gets into the named control-loop thing, so these are not just
the products of my demented mind.  They are the products of the demented
minds of people who get paid lots of money to think of them.
-- 
	Roland McGrath
ARPA: roland@rtsg.lbl.gov roland@lbl-rtsg.arpa
UUCP: ...!ucbvax!lbl-rtsg.arpa!roland

val@wsccs.UUCP (Val Kartchner) (03/14/88)

In article <1170@ucsfcca.ucsf.edu>, rk9005@cca.ucsf.edu (Roland McGrath) writes:
...(Some things deleted)...
> things like "break 2;" (e.g.,
> 	while (x > 0) { while (y != -1) { if (a) break 2; } }
> ), which gets into the named control-loop thing, so these are not just
> the products of my demented mind.  They are the products of the demented
> minds of people who get paid lots of money to think of them.


     I also think that there should be something like "break 'n';" (Where
     'n' is a constant integer.  Variables would be interesting and floats
     highly ambiguous.)  I've often been deep in multiple loops, and wanted
     to get out a few levels.  Most of the time, I have all the loops that I
     want to exit in a subroutine, and just return, but sometimes I can't
     afford the time for the function call and the return.  This same time
     critical restriction is for testing a "flag" variable at EVERY loop
     condition; I can't always afford the time.

     /* THE WAY IT IS NOW */         /* WITH "break 'n'" */
     void function()                 int another()
     {                               {
       while(....)                     do
	 do                            {
	 {                               ...
	   for(...)                      for(...)
	   {                             {
	     ...                           while(....)  /* funtion() */
	     if(...)                         do
	       return;                       {
             ...                               for(...)
           }                                   {
         } while(...);                           ...
     }                                           if(...)
                                                   break 3;
     int another()                               ...
     {                                         }
       do                                    } while(...);
       {                                   ...
	 ...                             }
	 for(...)                      }
	 {                           }
	   function()
           ...
         }
       }
     }


     A similar difficulty could be bypassed in the "switch" statement if
     this were allowed:

     for(flag=TRUE;flag;)              while(TRUE)
     {                                 {
       ...                               ...
       switch(function())                switch(function())
       {                                 {
	 case ...:                         case ...:
	 case ...:                         case ...:
	   ...                               ...
	   break;                            break;
         default:                          default:
	   flag = FALSE:                     break 2;
	   break;                        }
       }                                 ...
       ...                             }
     }


     Remember, I ask this to increase the usability of C (C is my computer
     language of choice), but it must be used with care.  It would tend to
     disabiguize some complex looping structures, but it must not be
     overused as "goto" often is.
-- 
---  /\  ------------ Val Kartchner  {UT@WSC} ---- #include <flamesuit.h> -----
    /\/\  .    /\   | "Those who don't understand VMS are condemmed to reinvent
   /    \/ \/\/  \  |  Unix; those who understand VMS and Unix use VMS."
==/ U i n T e c h \====!ihnp4!utah-cs!utah-gr!uplherc!sp7040!obie!wsccs!val====

rsalz@bbn.com (Rich Salz) (03/20/88)

In comp.lang.c (<316@wsccs.UUCP>), val@wsccs.UUCP (Val Kartchner) writes:
>     I also think that there should be something like "break 'n';" (Where
>     'n' is a constant integer. ...

This is not a safe idea.  Suppose you have some multi-level lopping:
	while () {
	    for () {
		/* while () */
		    while () {
			....
			break 3;
		    }
	    }
	}
What happens if you uncomment the third line?


PLEASE!  Take this discussion elsewhere.  Go use comp.lang.pascal or
something now; this stopped being C specific long ago...
	/r$
-- 
Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.

g-rh@cca.CCA.COM (Richard Harter) (03/20/88)

In article <316@wsccs.UUCP> val@wsccs.UUCP (Val Kartchner) writes:

	... suggesting a break n construct to escape n levels up.

Some languages have this.  It doesn't really work very well.  The
problem is that it is a maintenance nightmare.  If you have deeply
nested code (and that is where this thing would be used) and you
change an intermediate level of nesting you also have to change all
of those lower level 'break n's.  Moreover it can be, shall we say,
obscure as to where that 'break 5' is returning control to.

I am inclined to believe that labelled escapes are somewhat better.
We have already gone over this one, and several people with large
clubs have convinced me that it is not worth bothering with.

The situation boils down to this:  There is no good way in block
structure code to deal with multi-level escapes.  It appears to be
a fundamental property of block structured code.

There is only one real cure:  Don't write deeply nested code that
needs multi-level escapes.

-- 

In the fields of Hell where the grass grows high
Are the graves of dreams allowed to die.
	Richard Harter, SMDS  Inc.

terry@wsccs.UUCP (terry) (03/20/88)

In article <316@wsccs.UUCP>, val@wsccs.UUCP (Val Kartchner) writes:
>      I also think that there should be something like "break 'n';" (Where
>      'n' is a constant integer.  Variables would be interesting and floats
>      highly ambiguous.)  I've often been deep in multiple loops, and wanted
>      to get out a few levels.  Most of the time, I have all the loops that I
>      want to exit in a subroutine, and just return, but sometimes I can't
>      afford the time for the function call and the return.  This same time
>      critical restriction is for testing a "flag" variable at EVERY loop
>      condition; I can't always afford the time.

	Why not use a 'goto'?  This is precisely what it's there for...
discontinuous transfer of control.  A goto would eloquently avoid the
need to test a flag variable, as you would have to if you implimented all
your code with while()'s, and it usually compiles to a single machine
instruction (JMP #addr), thereby satisfying your time constraints.

[examples of 'break n' code deleted]

>      A similar difficulty could be bypassed in the "switch" statement if
>      this were allowed:

[a rather obscure for-loop-to-avoid-a-goto deleted]

Again, why not use a goto?  Is it the current indoctrination in computer
science classes to "avoid goto's at all costs, even if it increases code
complexity and execution time"?  The language feature is _there_ for handling
of abnormal conditions.

>      Remember, I ask this to increase the usability of C (C is my computer
>      language of choice), but it must be used with care.  It would tend to
>      disabiguize some complex looping structures, but it must not be
>      overused as "goto" often is.

There are several problems with this.  The first and foremost is that you are
suggesting something that is _not_ simplifying.  How is the need to count
braces to determine where you are going to end up simpler than an explict
labeling of where you want control to resume?  It seems to me that if your
code did this:

	while( 1) {
		switch( var) {
		case 1:
			...
			break;
		...
		default:
			if( cond)
				break 2;
			break;
		}
	}

and it changed (say you forgot to do something on the condition 'cond'), you
would have to be very careful to make sure you were breaking the approprite
number of levels... something which would have been automatic, had you used
a goto.

As an old 6502 assembly programmer, you should realized that you are simply
exchanging a jump for a jump relative... in other words, renaming the goto
and making the execution path more obscure, NOT making it clearer.


| Terry Lambert           UUCP: ...{ decvax, ihnp4 }                          |
| @ Century Software          : ...utah-cs!uplherc!sp7040!obie!wsccs!terry    |
| SLC, Utah                                                                   |
|                   These opinions are not my companies, but if you find them |
|                   useful, send a $20.00 donation to Brisbane Australia...   |
| 'There are monkey boys in the facility.  Do not be alarmed; you are secure' |

mcdonald@uxe.cso.uiuc.edu (03/20/88)

>	... suggesting a break n construct to escape n levels up.

>Some languages have this.  It doesn't really work very well.  The
>problem is that it is a maintenance nightmare.  If you have deeply
>nested code (and that is where this thing would be used) and you
>change an intermediate level of nesting you also have to change all
>of those lower level 'break n's.  Moreover it can be, shall we say,
>obscure as to where that 'break 5' is returning control to.

>I am inclined to believe that labelled escapes are somewhat better.
>We have already gone over this one, and several people with large
>clubs have convinced me that it is not worth bothering with.

>The situation boils down to this:  There is no good way in block
>structure code to deal with multi-level escapes.  It appears to be
>a fundamental property of block structured code.

>There is only one real cure:  Don't write deeply nested code that
>needs multi-level escapes.

C has a construct just exactly for this situation. It is easy to use,
portable, and very easy to maintain, because it doesn't depend
on the way loops nest:

while ( ick) {
    for (i = 2633; i < 7399; i += 23 ){
        do {
            while(foo()   ) {
                 ...
                 if(We_finished_early) goto all_the_way_out;
            }
        } while(mm < -11 );
     }
 }

all_the_way_out:
       ...

Doug McDonald

brianc@cognos.uucp (Brian Campbell) (03/28/88)

In article <316@wsccs.UUCP> val@wsccs.UUCP (Val Kartchner) writes:
> I also think that there should be something like "break 'n';" (Where
> 'n' is a constant integer.  Variables would be interesting and floats
> highly ambiguous.)  I've often been deep in multiple loops, and wanted
> to get out a few levels.

I brought this one up some time ago.  I think the response was the
usual "lack of prior art."  My suggestion was to add labels to looping
constructs:

    while (...) :top
        while (...)
            break :top;
        if (...)
            continue :top;

The label is far less confusing and requires less maintenance than
specifying the number of levels to exit.  It should also make the
compiler's job easier since it is specifically told that interior
statement blocks may be exited abnormally.

I think the syntax is interesting.  It resembles a label "in reverse"
and in fact tells the compiler to insert a label at the end of the
current statement block.  I don't know where braces should go though...
-- 
Brian Campbell        uucp: decvax!utzoo!dciem!nrcaer!cognos!brianc
Cognos Incorporated   mail: POB 9707, 3755 Riverside Drive, Ottawa, K1G 3Z4
(613) 738-1440        fido: (613) 731-2945 300/1200, sysop@1:163/8

rbutterworth@watmath.waterloo.edu (Ray Butterworth) (03/29/88)

In article <2571@cognos.UUCP>, brianc@cognos.uucp (Brian Campbell) writes:
> In article <316@wsccs.UUCP> val@wsccs.UUCP (Val Kartchner) writes:
> > I also think that there should be something like "break 'n';" (Where
> > 'n' is a constant integer.  Variables would be interesting and floats
> > highly ambiguous.)  I've often been deep in multiple loops, and wanted
> > to get out a few levels.
> My suggestion was to add labels to looping constructs:
>     while (...) :top
>         while (...)
>             break :top;
>         if (...)
>             continue :top;
> The label is far less confusing and requires less maintenance than
> specifying the number of levels to exit.  It should also make the
> compiler's job easier since it is specifically told that interior
> statement blocks may be exited abnormally.

But that is not really any clearer than what is already available
in the language:


    for ( ; 0 != (file=fopen(...)); fclose(file)) samefile: {

        while (0 != (line = fgetl(...))) sameline: {

            for (index=0; 0 != (c=line[index]); ++index) samechar: {

                ...
                if (blah()) goto nextfile;
                blahblah();
                if (blahblahblah()) goto sameline;
                ...

                nextchar:;
            }
            nextline:;
        }
        nextfile:;
    }

And I don't feel the slightest guilt in using "goto" in this way.

gillies@uiucdcsp.cs.uiuc.edu (03/31/88)

Believe it or not, there is still a home for gotos in this world.  The
"religion" you learned in college is not a universal dogma.
Sometimes, gotos are perfectly justifiable because they vastly
simplify and clarify you code.