From leavens@judy.cs.iastate.edu. Tue Feb 12 17:13:00 1991
Date: Tue, 12 Feb 91 17:07:35 CST
From: leavens@judy.cs.iastate.edu. (Gary Leavens)
To: leavens@judy.cs.iastate.edu
Subject: c closures

Dennis Ritchie writes:

>But C has functions as objects too, consider the following:

>typedef int (*func)();

>int takes_y(y)
>     int y;
>{ return(x + y); }

>func cadd(x)
>      int x;
>{ return(takes_y); }

>main()
>{ printf("%i\n", (cadd(2))(3)); }

>I just about have this working, and it seems like it does the
>same thing as the Scheme code.  (Only problem is that the variable
>"x" used in "takes_y" is undefined, but I'll fix that soon.)

Dennis and his problem with the variable "x" point out the value
of Scheme's closures.  The thing is that (cadd 2) in Scheme
is a closure, and so automatically keeps track of the binding
of x to 2.  If we work out Dennis's problem with "x" we can see
even more of the value of closures in Scheme.  Consider the
following:

typedef int (*func)();
typedef struct {func f; int x} x_closure_struct, *closure;

int add(x,y)
     int x,y;
{ return(x + y); }

closure cadd(x)
     int x;
{
  closure c;
  c = (closure) malloc(sizeof(x_closure_struct));
  /* ignoring the check for NULL */
  c->f = add;
  c->x = x;
  return(c);
}

int invoke_closure(c, arg)
     closure c;
     int arg;
{ return((c->f)(c->x,arg)); }

main()
{ printf("%i\n", invoke_closure(cadd(2),3)); }

I changed Ritchie's "takes_y" procedure into "add",
but the most significant change is to have "cadd" return
a "closure", which is (as in Scheme) a structure containing
both a function (add) and a binding for x.  In this way
one can have multiple closures returned by "cadd" lying around.

If one made "x" a global variable in Ritchie's program,
then there would be a problem in the following:
  func add2, add3;
  add2 = cadd(2);
  add3 = cadd(3);
  printf("%i\n", add2(27));
which will print 30, not 29.

To summarize, lambda builds closures in Scheme.
And a closure is a function + an environment.
  Gary


