1. About GOTO (was RE: fixed windows)

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 blink

Hans Peter Willems

new topic     » topic index » view message » categorize

2. Re: About GOTO (was RE: fixed windows)

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

new topic     » goto parent     » topic index » view message » categorize

3. Re: About GOTO (was RE: fixed windows)

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

new topic     » goto parent     » topic index » view message » categorize

Search



Quick Links

User menu

Not signed in.

Misc Menu