1. About GOTO (was RE: fixed windows)
- Posted by Peter Willems <peter at integratedmoves.com> Aug 06, 2003
- 399 views
Well..... I like to add a bit more perspective to the "goto" discussion and specifically why I said that planning in software design makes it unneeded. First of all, in Lineair languages (that execute their code in a straight top-down manner), goto is the only way to have conditional code. But in that case there is no problem with using goto because it is only used to step over unused conditions. jbrown105 at speedymail.org wrote: > The idea of not having goto support, is to replace it with better > controlled > and restricted "goto"s which prevent the unreadablility. Whether or not > this > is a good thing depends on the skill of the programmer, the level of > difficulty > of the language overall (i.e. if its asm code then a goto or jmp isnt > gonna > make it that much more unreadable), and personal opinion. jbrown does a fair job of explaining here and I like to add some more information: The problem with goto is that it does not force you to think about what you are going to do next, that is after you have used that goto. The goto statement is known for encouraging quick and dirty programming and is almost always used in ad hoc programming. Besides that, goto goes against any form of structured modularization of code. This is one of the main reasons why N. Wirth omitted goto in Pascal and many languages have followed that omission. The point that I was trying to make is that a little planning before you actual start coding goes a long way in building understandable and maintainable code. The first program I wrote myself was a CAD-program. It had grids with locking, a full windowed interface with mouse control and pulldown menus, symbol libraries, mathematic functions and much more. It was written on a MSX2 machine and crammed into 24 Kb basic. The only way to develop such a program in so little space was to plan and develop it largely before any coding took place. Obviously I didn't use any goto statements. I'm not saying that goto is evil (although every informatics teacher will tell you) but the availability of a goto command generally does more bad than good, so there is a reason why many languages don't implement it. On a side note: if anyone is interested in stuff like Cleanroom Software Engineering, Software Quality Assurance, the Capability Maturity Model, etc. let me know Hans Peter Willems
2. Re: About GOTO (was RE: fixed windows)
- Posted by David Cuny <dcuny at LANSET.COM> Aug 06, 2003
- 385 views
Peter Williems wrote: > I'm not saying that goto is evil (although every informatics > teacher will tell you) but the availability of a goto command > generally does more bad than good, so there is a reason why many > languages don't implement it. I suspect the reasons are more pragmatic. For example, I couldn't implement GOTO in the Eu (Euphoria written in Euphoroia) because the code was stored in a tree structure. Since Euphoria won't give you the address of an arbitrary node, you can't just jump to a node - you have to traverse the tree. So coding Goto is non-trivial. In other languages (Lua 4, FORTH) loop values are often placed on the stack, incremented and ultimately discarded by the END FOR construct. Jump out of a FOR loop, and you leave junk on the stack. I can imagine that there might be some similar issues in Euphoria, where an arbitrary JUMP might cause a sequence not to be dereferenced properly. (I suspect that Robert's too clean a coder for that to be the case.) The main reason that I can see for a GOTO is to get you out of a deeply nested routine. I've seen two interesting approaches to this. The first comes from ABC, which used the idea of refinements. This allows breaking a routine into smaller routines; something along the lines of: procedure foo() integer a foo1() foo2() refinement foo1() integer b a = 12 end refinement refinement foo2() integer b a = 22 exit refinement end refinement end procedure Refinements shared the parent's local variables, but could have their own private variables. Refinements are great when you've got this complex routine that needs simplification, but you don't want to declare a bunch of global variables. With refinements, you can just call EXIT REFINEMENT and you're back to the caller. So if you've got something like this: integer i, j, k for i = 1 to 100 do for j = 1 to 100 do for k = 1 to 100 do printf( "%d %d %d\n", {i, j, k } ) goto myExit: end for end for myExit: end for you could write it as a refinement like so: integer i, j, k for i = 1 to 100 do nestedLoops() end for refinement nestedLoops() for j = 1 to 100 do for k = 1 to 100 do printf( "%d %d %d\n", {i, j, k } ) exit refinement end for end for end refinement Without refinements, i, j and k would have to be declared as globals. The other way I've seen it handled is with a try/catch construct. This would look something like: integer i, j, k for i = 1 to 100 do try for j = 1 to 100 do for k = 1 to 100 do printf( "%d %d %d\n", {i, j, k } ) throw myError end for end for catch myError end try end for The try/catch feels like an over-engineered solution, but it's got a lot to recommend for it. It's structured, it's easy to understand, and it would solve a lot of the problems with the way errors are (and are not) handled in Euphoria. On the down side, neither of these solutions are as simple as a GOTO. -- David Cuny
3. Re: About GOTO (was RE: fixed windows)
- Posted by David Cuny <dcuny at LANSET.COM> Aug 07, 2003
- 403 views
I've implemented REDO, BREAK and CONTINUE in my own BASIC interpreter. Additionally, there is a ELSE clause on all the control structures, so if they complete without hitting a BREAK clause, the THEN executes: for i = 1 to length( s ) if s[i] = 999 then break end if else printf( "999 was not found" ) end for It saves having to set up a flag marking that something was found, and is cheap to implement. What none of these provides is the ability to jump out an arbitrary number of levels - for example: for i = 1 to 10 while a < length( s ) for j = 1 to 10 for k = 1 to 10 -- LEAVE HERE... end for end for end while -- ... AND JUMP TO HERE end for For this, TRY/CATCH is probably the best thing: integer MyError = NEW_ERROR( "My custom error" ) for i = 1 to 10 TRY while a < length( s ) for j = 1 to 10 for k = 1 to 10 THROW MyError end for end for end while CATCH { MyError } END TRY end for Another option would be to implement a more limited version of TRY/CATCH, like this: for i = 1 to 10 while a < length( s ) for j = 1 to 10 for k = 1 to 10 THROW MyError end for end for CATCH { MyError } end while end for Note the CATCH clause is attached to the WHILE loop. THROW would cause a continuous BREAK until a CATCH clause is found. The problem with this is that it gives you less granularity than if you had a TRY control structure. Also, TRY has a cool FINALLY clause, which guarantees to always execute, whether or not an error was thrown, even if a RETURN is encountered in the clause. This helps ensure that resources that were taken are always disposed of. -- David Cuny