Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP
Posting-Version: version B 2.10.1 6/24/83; site mit-eddie.UUCP
Path: utzoo!watmath!clyde!burl!mgnetp!ihnp4!mit-eddie!nessus
From: nessus@mit-eddie.UUCP (Doug Alan)
Newsgroups: net.lang
Subject: Re: Gotos; tail-recursion
Message-ID: <2042@mit-eddie.UUCP>
Date: Tue, 5-Jun-84 03:15:58 EDT
Article-I.D.: mit-eddi.2042
Posted: Tue Jun  5 03:15:58 1984
Date-Received: Wed, 6-Jun-84 06:21:52 EDT
References: <1979@mit-eddie.UUCP> <1986@mit-eddie.UUCP>
Organization: MIT, Cambridge, MA
Lines: 136


	From: gumby@mit-eddie.UUCP (David Vinayak Wallace):

>	Quite the contrary; throw (*throw) UNWINDS the stack, jumping
>	backwards.  The two big features of throw are 1> that it unwinds
>	the stack (rather than just setting the PC) 2> That it has a
>	scope -- it's only applicable within the lexical (Scheme) or
>	dynamic (Lisp) scope of the corresponding catch.  In my opinion,
>	the dynamic throw is almost as bad as ordinary GOTO -- you can't
>	clearly see the flow of control by just reading the code.

It doesn't matter that the label comes before the jump.  The jump is
still in a forward direction.  (I'm using "forward" to mean the
direction that can't possibly cause you to loop.)  The following two
pieces of code do the same thing, even though one has the label at the
beginning, and one at the end:

(1)	(print (*catch 'foo
	          (let ((x 1))	
	            (do-forever (print x)
	     			(setq x (1+ x))
	     			(if (= x 10.)
				    (*throw 'foo 3.1416))))))


(2)	po: stream := stream$primary_output()
	x: int := 1
	while true do
	   stream$putl(po, int$unparse(x))
	   x := x + 1
	   if x = 10 then exit foo(3.1416)
			  end
	   end
	   	except when foo(y:real):
		   stream$putl(po, real$unparse(y))
		   end

In both the jump goes in the same direction.

And who says that GOTOs only set the PC?  If you have a language that
allows GOTOs, and it also lets you GOTO out of a block that has it's own
local variables, then it better do more than just setting the PC (unless
the compiler has already accounted for this by preallocating the
variables).  Here part of the stack must be unwound.

And, not only that, but who says that GOTOs can't have a scope?  Lisp
has GOs, but you can't GO out of the PROG statement.  In some Pascals
there are GOTOs, but you must declare a label, and you can't jump to
that label if you are not in its scope.

It seems to me that a GOTO is any statement that involves disrupting the
natural flow of control of the program, and transfering control to
someplace else that has been named.  Unrestricted GOTOs, if used
unrestrictedly are definitely bad things.  But some types of GOTOs are
definitely useful (like loop exits, etc.)  We have to decide what
restrictions on GOTOs make them palatable.

I agree that dynamic throws are incredibly bad.  I should have been more
restrictive in my specification of good GOTOs.  Not only are the labels
for both THROW and CATCH computed at run-time, but even if they weren't,
you still wouldn't always be able to tell just by looking a program
where a THROW is THROWing to.  ADA also has this problem with its error
system.  CLU does NOT have this problem with its EXIT or SIGNAL (for
signalling errors) system.  I haven't yet decided whether lexical THROWs
are very good things.  They're much better than dynamic THROWs, but you
can still do some pretty weird things.

>    Unless you shun other structured iterative constructs (e.g. 'for'
>    in c) I don't see why to shun tail-recursion.  It's not a
>    generalisation of goto; it's only useful in one place goto is.

No, you're wrong.  Tail recursive procedure calls are a generalization
of GOTO.  They are at least as powerful.  You could implement GOTO with
tail recursive procedure calls.  Following is a simple translation of a
BASIC program with GOTOs to a (Bad!) Lisp program with tail recursion:

(1)
	3 FO = 0
	5 GOTO 10
        7 END
	10 PRINT "Hello"
	20 FO = FO + 1
	30 IF FO = 10 THEN 50
        40 GOTO 10
        50 GOTO 7


(2)	(defun L3 () (setq fo 0) (L5))
	(defun L5 () (L10))
	(defun L7 () nil)
	(defun L10 () (print "Hello") (L20))
	(defun L20 () (setq fo (1+ fo)) (L30))
	(defun L30 () (if (= fo 10) (L50)
	 	      	(L40)))
	(defun L40 () (L10))
	(defun L50 () (L7))

Of course, you could do the same with without tail recursion, but you
would probably get discouraged pretty fast when you started getting
stack overflows if your program ran for more than a few thousand steps.
Without tail recursion, this would never discourage you, so if you might
be tempted to do horrible things like this.  I'm not saying that tail
recursion is bad.  Actually I think it is a good idea.  But I think this
problem is something to think about.

>     It's not clear I'd call Lisp an object-oriented language.  The worst
>     confusion endengered with the Lisp class we're teachine at Stanford
>     right now is with object-oriented systems.  My complaint with teaching
>     langages like Pascal is that all the features designed to make it easy
>     to program in actually get in the way of the studen't understanding of
>     the nature of programming, by presenting arbitrary distinctions between
>     "system" and "user" code (functions and operators, and ...), and by
>     presenting system-dependent abstractions (say , the io system in
>     Pascal).  Whatever else its failings, at least lisp is more consistent
>     in its view of the world.

Well I know that Smalltalk people use "object oriented" to mean that
operations are run-time polymorphic on the type of the argument.  But
CLU people generally use object oriented to mean that something like
that there are no second-class objects (though they've stopped using the
term as much ever since Smalltalk people stole the term out from under
them. . . .)  In Pascal you can create integers, reals, and booleans,
and return them to a higher scope than that in which they were created,
but you can't do that with arrays, records, etc.  In CLU, Lisp, and
Smalltalk you can do this with an object of any type.  I like this
definition of "object oriented" better, because it's clear why it's name
is is "object oriented", and I don't see what there is in the name that
implies generics.  Though I think generic operations are great, I think
that this concept should be called something other than "object
oriented".
-- 
				-Doug Alan
				 mit-eddie!nessus
				 Nessus@MIT-MC

				"What does 'I' mean"?