[comp.object] Re^2: Continuations

murthy@alsvid.cs.cornell.edu (Chet Murthy) (11/29/89)

peterd@cs.washington.edu (Peter C. Damron) writes:


>I just had to reply when I saw this.  C and C++ are definitely "lexically
>scoped" (I would prefer to call it statically scoped).

Yes, they are, but they don't provide support for closures as
first-class objects (the funarg problem).  So they don't provide
"full" support for lexical scoping.  Scheme/ML do.
--chet--

	--chet--
	murthy@cs.cornell.edu

chase@Ozona.orc.olivetti.com (David Chase) (11/29/89)

In article <34657@cornell.UUCP> Chet Murthy writes:
>peterd@cs.washington.edu (Peter C. Damron) writes:

>>I just had to reply when I saw this.  C and C++ are definitely "lexically
>>scoped" (I would prefer to call it statically scoped).

>Yes, they are, but they don't provide support for closures as
>first-class objects (the funarg problem).  So they don't provide
>"full" support for lexical scoping.  Scheme/ML do.

Try "lexical scope with nested procedures" for "lexical scope", and I
think you'll fix your misunderstanding.  (I got this from the Dragon
Book, 2nd ed., and I once abused the terminology in the same way).  C,
Pascal, Modula-3, and Scheme all have lexical scope -- the bindings
can be determined by examining the program text.  In addition, all
four use the "most-closely-nested rule" for resolving bindings.

However, the languages listed differ in their treatment of nested
procedures:

C         forbids them  (no closures).

Pascal    allows them, but (in Pascal Classic, at least) forbids
          their assignment to variables, use as parameters to
	  procedures, or use in a RETURN.  (no closures, because it
	  turns out that a display can be used).

Modula-3  allows them, but forbids their assignment to variables or
          their use in a RETURN.  (closures needed, but must obey
	  stack lifetime rules).  (I hope this example isn't too
	  obscure -- I'm rather familiar with it at the moment).

Scheme    allows them (garbage-collected closures, except where
          optimized away).

Now (returning to continuations [pun unintended]), it happens that
many many things can be defined in terms of continuations, including
exception handling.  With closures, it is possible to implement some
really interesting exception handlers, but liberal use of closures and
continuations can (read will, with current technology) interfere with
optimization (in particular, it interferes with register allocation --
if you don't map the same variables to the same registers at the
appropriate program points, it gets very very messy, much like setjmp
and longjmp).

One limited use of continuations is actually very much like
setjmp/longjmp (though the syntax is different).  In C, it might go
something like (ignore the type-checking, and pretend we have nested
procedures):

typedef any_type (*continuation)();

f(...)
  {
  int key, x;
  tree t;

  int search(t,K) tree t; continuation K;
  {
  /* RETURN immediately via K if found */

    if (match(key, t)) K(t);
    search(left(t),K);
    search(right(t),K);

  /* Normal return for failure */
  }

  tree g(K) continuation K;
     {
       /* Find key in tree t, returning quickly if found. */
       search(t,K);

       /* If search returns at all, then it failed to find anything,
          so we return NULL */
       return NULL;
     }
  ...
  x = call_with_curr_continuation(g);
  ...
  }

This should illustrate the (ab)use of continuations in a simple,
quick-return fashion.  More sophisticated use of continuations will
store them in global variables and/or return them.  This allows the
program to "return to" (a second time) an "inactive" call frame.  The
implementation of these is a little more heavyweight, but it does
allow easy descriptions of backtracking algorithms and iterators.
Note the usefulness of lexical scope in this example.

David

chewy@apple.com (Paul Snively) (11/29/89)

In article <34657@cornell.UUCP> murthy@alsvid.cs.cornell.edu (Chet Murthy) 
writes:
> >I just had to reply when I saw this.  C and C++ are definitely 
"lexically
> >scoped" (I would prefer to call it statically scoped).
> 
> Yes, they are, but they don't provide support for closures as
> first-class objects (the funarg problem).  So they don't provide
> "full" support for lexical scoping.  Scheme/ML do.
> --chet--

I think this is why Scheme lends itself so readily to the implementation 
of a wide variety of "object-oriented" models: Scheme makes no a priori 
distinction between code and data (that is, functions, or closures if you 
wish to be more precise, can be passed as arguments, returned as values, 
stored in other data structures, etc. etc. etc.)

Of particular interest from an object-oriented standpoint, I think, is the 
fact that with full upward continuations and closures, you can VERY easily 
write a function that takes a list of arguments and returns the value of 
some arbitrary argument, and when you invoke another function (say fail), 
backtracking is performed to the last decision point, and one of the OTHER 
arguments' values is returned, etc. until there are no more arguments.  
This non-deterministic programming system is particularly useful for 
implementing delegating object systems, and can be implemented trivially 
in Scheme ("trivially" meaning in about one and a half 8 1/2" x 11" pages 
printed on a LaserWriter in 10-point Courier).  It's also worth noting 
that this non-deterministic example, using continuations and closures, 
ships with MacScheme 2.0 or later (in case you've got a Mac and are 
curious about it).

__________________________________________________________________________
Just because I work for Apple Computer, Inc. doesn't mean that they 
believe what I believe or vice-versa.
__________________________________________________________________________
C++ -- The language in which only friends can access your private members.
__________________________________________________________________________

marti@ethz.UUCP (Robert Marti) (11/29/89)

In article <34657@cornell.UUCP>, murthy@alsvid.cs.cornell.edu (Chet Murthy)
writes:
| peterd@cs.washington.edu (Peter C. Damron) writes:
| > C and C++ are definitely "lexically  scoped".
|
| Yes, they are, but they don't provide support for closures as
| first-class objects (the funarg problem).  So they don't provide
| "full" support for lexical scoping.  Scheme/ML do.

Indeed, C and C++ do not even allow a procedure to be declared local to
another procedure.  Maybe nesting is not only for the birds, after all  ;-)

-- 
Robert Marti                      Phone:      +41 1 256 52 36
Institut fur Informationssysteme
ETH-Zentrum                       CSNET/ARPA: marti%inf.ethz.ch@relay.cs.net
CH-8092 Zurich, Switzerland       UUCP:       ...uunet!mcvax!ethz!marti