peter@thirdi.UUCP (Peter Rowell) (09/07/89)
In article <7598@goofy.megatest.UUCP> djones@megatest.UUCP (Dave Jones) writes: ... >I just now produced one [a benign goto] ... ... > 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 agree with David, since in C there really aren't any beautiful ways to do the above. One thing I would have loved to have seen introduced by ANSI would have been "named blocks", but I am sure that parsing them is a bitch. Borrowing heavily from SAIL, a named block could be defined as one that has a string constant immediately following the opening curly brace. The matching closing curly could have an optional string which, if present, must match exactly the one attached to the opening brace. This second part gives "begin/end" checking over arbitrarily nasty nestings (like in the big switches often found in command interpreters, etc.). The name is available as an optional argument to "break" and "continue". If a name is missing, they (break/contiue) act as they do now. If included, they allow multi-level break'ing and continue'ing. Given this "improvement", the above might have been written: while(rule = (Rule*)Queue_iter_next(&rule_iter)) { "outer loop" while(rsym = (Symbol*)Queue_iter_next(&rsym_iter)) { "inner loop" switch (derives(rsym)) { "switch 1" case derives_nothing: continue "outer loop"; /* <<== next iteration of outer */ case derives_something: /* ... */ break; /* a normal break */ default: break "inner loop"; /* <<== falls out the bottom of inner */ } "switch 1" } "inner loop" /* random code */ } "outer loop" which I believe is much more readbale. Not all of the names were necessary, but I was having fun. Sigh, maybe we can do this in the next language..... ---------------------------------------------------------------------- Peter Rowell peter@thirdi.UUCP Third Eye Software, Inc. (415) 321-0967 Menlo Park, CA 94025 "There are already enough names." Lao Tze
davidsen@crdos1.crd.ge.COM (Wm E Davidsen Jr) (09/07/89)
In article <475@thirdi.UUCP>, peter@thirdi.UUCP (Peter Rowell) writes: | One thing I would have loved to have seen introduced by ANSI would have | been "named blocks", but I am sure that parsing them is a bitch. | Given this "improvement", the above might have been written: | | while(rule = (Rule*)Queue_iter_next(&rule_iter)) { "outer loop" | while(rsym = (Symbol*)Queue_iter_next(&rsym_iter)) { "inner loop" I think the idea of naming the loop rather than the block, as suggested earlier, would be easier to parse. Ex: while loop1 (a < b) { while (b = foo(2)) { /* stuff here */ if (m > 20) continue loop1; /* specifies the scope of the loop */ } /* this is where 'continue loop1' transfers */ } Disclamer: this is not my idea, and I am not offering an opinion on including it in the language. I think discussion of these features is a good way to have the major pitfalls discovered before someone has implemented them. -- bill davidsen (davidsen@crdos1.crd.GE.COM -or- uunet!crdgw1!crdos1!davidsen) "The world is filled with fools. They blindly follow their so-called 'reason' in the face of the church and common sense. Any fool can see that the world is flat!" - anon
bvs@light.uucp (Bakul Shah) (09/07/89)
In article <475@thirdi.UUCP> peter@thirdi.UUCP (Peter Rowell) writes: >In article <7598@goofy.megatest.UUCP> djones@megatest.UUCP (Dave Jones) writes: >... >>I just now produced one [a benign goto] ... >... >> 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 agree with David, since in C there really aren't any beautiful ways >to do the above. > >One thing I would have loved to have seen introduced by ANSI would have >been "named blocks", but I am sure that parsing them is a bitch. > > [a version of the above example using named blocks] Note that the `benign' goto above can be removed also by use of a procedure. It can also improve readability (which is the underlying theme here). static foo(rule) { /* rename `foo' to something better */ ... while(rsym = (Symbol*)Queue_iter_next(&rsym_iter)) { ... switch (derives(rsym)) { case derives_nothing: return; } } caller_of_foo(..) { ... while(rule = (Rule*)Queue_iter_next(&rule_iter)) { ... foo(rule); } } I find short procedures and ones with simple control structues easy to read. But ones using nested loops and control jumps to various levels of switches and loops are hard to grasp. Breaking an inner loop into a separate procedure (hopefully) forces one to think about making the connection between the caller and callee relatively thin. Also note that modern compilers are capable of inlining such one time use procedures (with a little help from the user). This is not to argue merits of named blocks but to point out that existing features are not only capable of banishing gotos but can also improve readability. On a related note, one feature I miss in C is nested procedures. Without them one ends up using global variables or passing lots of arguments or avoids using a procedutre altogether because the code that can be broken off into a separate procedure is just too tightly coupled with its environment and would make for a very messy interface (or force global var usage). Oh well.... -- Bakul Shah <..!{ames,sun,ucbvax,uunet}!amdcad!light!bvs>
djones@megatest.UUCP (Dave Jones) (09/08/89)
From article <1989Sep7.162909.6638@light.uucp>, by bvs@light.uucp (Bakul Shah): > > Note that the `benign' goto above can be removed also by use of a > procedure. It can also improve readability (which is the underlying > theme here). Just use a "return" to jump out of the procedure, rather than a "goto" to jump out of the block. Sorry, but I don't see that as an improvement. But there is a problem you seem to have overlooked. To keep the same functionality, you are going to have to pass pointers to all local variables into the newly created procedure, and replace all references to the local procedures with dereferenced pointers. (C++ "reference" parameters would save the day, but we're talking C, not C++) A block of code such as the one under discussion simply does not belong in another procedure, IMHO. > > Also note that modern compilers are capable of inlining such one > time use procedures (with a little help from the user). > Name one C compiler that does that. > This is not to argue merits of named blocks but to point out that > existing features are not only capable of banishing gotos but can > also improve readability. We've known a long long time that gotos can be banished with existing features. But is the cure worse than the complaint? I maintain that my goto is benign. Creating a new procedure with scads of pointer dereferences is major surgery. > > On a related note, one feature I miss in C is nested procedures. > Sorry, we can't seem to agree on anything. "Nested procedures" is just the automation of that pointer-creation/dereferencing I talked about above. Usually there's one pointer for each lexical level, (the "display"), and each nested procedure indexes off these for all the "scoped" variables. Phooey on that. (Well, okay, since we are now in the realm of what might be, maybe one of those "modern compilers" could inline the code when appropriate.) > Without them one ends up using global variables or passing lots of > arguments or avoids using a procedutre altogether because the code > that can be broken off into a separate procedure is just too tightly > coupled with its environment and would make for a very messy > interface (or force global var usage). Oh well.... > At last! Agreement. This is indeed a problem. But it's a static problem. No need to bring a runtime display into the picture. One way to handle it might be a convenient macro mechanism: proc_which_would_otherwise_be_too_long() { int local_var; do_some_stuff(); do_some_more_stuff(); } where macro do_some_stuff() is { local_var = 0; /* Notice, it's still in scope */ /* blah, blah.. */ return; /* We can debate as to whether this returns * from the main procedure or from the macro. * The macro, I think. */ } It's sort of a cross between a macro and an inline procedure. It is like a nested-scope procedure, except that it accesses its parent's variables directly, not through a display, and of course, it can not call itself or any other "macro" procedure. Or, I could get by just fine with an editor that could name and hide blocks, and store such info with the source files. (Hypertext?) Then you could have this displayed... proc_which_would_otherwise_be_too_long() { int local_var; /* pooh on globals */ <<do_some_stuff();>> <<do_some_more_stuff();>> } If you clicked your mouse on the "do_some_stuff" area, the code would be expanded there. Click in the expanded area again, and it hides itself again. (If you work for one of those software companies, please do not patent this idea. Thank you. I hearby place it in the public domain.) This would work nicely in conjuction with the named blocks idea.
ok@cs.mu.oz.au (Richard O'Keefe) (09/08/89)
In article <475@thirdi.UUCP>, peter@thirdi.UUCP (Peter Rowell) writes: | One thing I would have loved to have seen introduced by ANSI would have | been "named blocks", but I am sure that parsing them is a bitch. In article <297@crdos1.crd.ge.COM>, davidsen@crdos1.crd.ge.COM (Wm E Davidsen Jr) writes: > I think the idea of naming the loop rather than the block, as > suggested earlier, would be easier to parse. I would point out that BCPL had named brackets $(NAMEHERE ..... $)NAMEHERE long before C was thought of, and that the BCPL code for the front end of the BCPL compiler is available in the book on BCPL. Far from being "a bitch" to parse, they are dead simple. Just treat all brackets as named with a possibly empty name, push the name onto a stack whenever you see a "{...", and whenever you see a "}..." check for a match with the top of the stack. We can't use '{' "string" in an extension to C, because a C statement may begin with a string. For example "abc"[i] == ch ? foo() : baz(); Since C statements can't start with colons, perhaps <opening brace> ::= '{' ':' <identifier> | '{' <closing brace> ::= '}' ':' <identifier> | '}' might do. PL/I has named brackets where a labelled END statement may stand in for any number of anonymous END statements as well; this is widely regarded as a mistake. Ada has loop labels (label:loop) and statement labels as well (<<label>> statement). All things considered, might we not be better off with compilers that can generate in-line code for nominated functions?
hascall@atanasoff.cs.iastate.edu (John Hascall) (09/08/89)
In article <7818@goofy.megatest.UUCP> djones@megatest.UUCP (Dave Jones) writes: }From article <1989Sep7.162909.6638@light.uucp>, by bvs@light.uucp (Bakul Shah): }> }> Also note that modern compilers are capable of inlining such one }> time use procedures (with a little help from the user). }> }Name one C compiler that does that. Ok. The VAX/VMS compiler. An excerpt from the help: CC /OPTIMIZE[=option] Controls whether optimization is performed by the compiler. /NOOPTIMIZE turns off the /PARALLEL qualifier. The two options are as follows: ... [NO]INLINE Specifies whether the compiler is allowed to perform the function inline optimization. John Hascall ISU Comp Center
chris@mimsy.UUCP (Chris Torek) (09/08/89)
In article <7818@goofy.megatest.UUCP> djones@megatest.UUCP (Dave Jones) writes: -Or, I could get by just fine with an editor that could name and -hide blocks, and store such info with the source files. (Hypertext?) -Then you could have this displayed... - - proc_which_would_otherwise_be_too_long() - { - int local_var; /* pooh on globals */ - - <<do_some_stuff();>> - <<do_some_more_stuff();>> - } Go to your nearby technical bookstore and look at copies of _TeX:_ _The_Program_ and _METAFONT:_The_Program_, by D. E. Knuth. >If you clicked your mouse on the "do_some_stuff" area, the code would >be expanded there. Click in the expanded area again, and it hides >itself again. (If you work for one of those software companies, please >do not patent this idea. Thank you. I hearby place it in the public >domain.) Too late :-) WEB has other features that make it ugly, but this one in particular is nice. -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163) Domain: chris@mimsy.umd.edu Path: uunet!mimsy!chris
merlyn@iwarp.intel.com (Randal Schwartz) (09/09/89)
In article <475@thirdi.UUCP>, peter@thirdi (Peter Rowell) writes: | One thing I would have loved to have seen introduced by ANSI would have | been "named blocks", but I am sure that parsing them is a bitch. | Borrowing heavily from SAIL, a named block could be defined as one that | has a string constant immediately following the opening curly brace. Perl has 'em. LINE: while ($_ = <stdin>) { # read a line into variable $_ ...; while ($something_needs_to_be_done) { ...; ...; next LINE if time > $quitting_time; # jump out to the outer loop ...; } ...; } Works pretty well. Just another Perl hacker, -- /== Randal L. Schwartz, Stonehenge Consulting Services (503)777-0095 ====\ | on contract to Intel, Hillsboro, Oregon, USA | | merlyn@iwarp.intel.com ...!uunet!iwarp.intel.com!merlyn | \== Cute Quote: "Welcome to Oregon... Home of the California Raisins!" ==/