From: pcg@aber.ac.uk (Piercarlo Grandi)
Newsgroups: comp.object
Subject: Classes are procedures, objects are closures in class based OO languages
Summary: class based OO languages demistifyed; important revelations on
	the role of seductive Nordic languages; relentless advertising
	for two books; what about me getting a life instead of writing
	such primer level obvieties;
Date: 22 Jan 93 17:02:23 GMT
	<PCG.93Jan14154212@decb.aber.ac.uk>
	<1993Jan15.033713.27130@netcom.com>
	<PCG.93Jan19235921@decb.aber.ac.uk>
Reply-To: pcg@aber.ac.uk (Piercarlo Grandi)
Organization: Prifysgol Cymru, Aberystwyth


on [Tue, 19 Jan 1993 23:59:21 GMT] I had written a little article to
show how (class based) OO was born out of making it possible to have
multiple persistent instances of procedure contexts (closures), to
explain my short description:

pcg> More precisely objects are values of a procedure instance
pcg> (closure/continuation) record type.

Rereading my article (I often find rereading my articles interesting as
I can learn new things from them :-> ;->) I have realized that the
example could have structured better, in particular in two steps, to
make more easily discernible the (Norse) legerdemain that is being
applied.

I hope the readership of this distinguished newsgroup will not be unduly
distressed by a further exposition of one of my pet subjects :->.

So, here it is again. Let's imagine we have the following Pascal
program fragment:

	  PROCEDURE complex(re, im : real);

	    TYPE complex_value = RECORD re,im: real; END;

	    VAR self : complex_value;

	    FUNCTION plus(other : complex_value) : complex_value;
	      VAR sum : complex_value;
	    BEGIN
	      sum.re := self.re + other.im;
	      sum.im := self.im + other.im;
	    END;

	  BEGIN
	    self.re := re;
	    self.im := im;
	  END;

This does not look very helpful. We can only deal with the values that
have been declared inside 'complex', and we can only operate on them in
the body of procedure complex. The fundamental reasons are that there
can be only one instance of a procedure at any one time (but for
recursion) and since this one instance cannot outlive it caller, its
local variables can only be accessed inside it.

But we can stipulate that like in Simula 67:

* Procedures may have multiple instances.

* A procedure instance context (its closure) may outlive the end of
  the execution of its body code.

* A procedure name defines also a type/mode, that of its closure,
  and one may declare pointers of such type/mode.

* A procedure instance is created by invoking it prefixed with 'NEW',
  and this returns a pointer to the instance.

* It is possible to access the local attributes of a procedure
  closure with dot notation.

Then we can write the following Pascal 67 program:

	PROGRAM oo_classes_are_procedures(output);

	  PROCEDURE complex(init_re, init_im : real);

	    VAR re,im : real;

	    FUNCTION plus(other : ^complex) : ^complex;
	    BEGIN
	      RETURN NEW complex(re+other^.re,i+_other^.im);
	    END;

	  BEGIN
	    re := init_re;
	    im := init_im;
	  END;

	  VAR i,u,s : ^complex;

	BEGIN
	  i := NEW complex(0.0,1.0);
	  u := NEW complex(1.0,0.0);
	  s := i^.plus(u);
	  writeln('s is (',s^.re,',',s^.im,')');
	END.

(note that this is identical to Simula 67 except for one extremely minor
detail; note also that since Pascal does not allow for pointers to
procedures, we can use '^ procedure_name' to mean 'pointer to procedure
instance', else we would have to have a way of disinguishing between the
type/mode of a procedure and that of one of its instances/closures).

To conclude, some observations:

* Like in Simula 67, we stipulated that one can only define *pointers*
  to procedure instances. This is actually not necessary in general, and
  some would argue that this is not desirable too (despite the not all
  unfavourable expirience with pointer based OO and non OO languages
  like Lisp, CLU, Simula 67, Smalltalk, and the first version of
  Eiffel). The reasons for which one could only have pointers to
  procedure instances (objects) in Simula 67 are incidental to the way
  it was derived from Algol 60, not essential to OO.

* The above situation is exactly the same as in in all well known class
  based OO languages, from Smalltalk to C++ to Eiffel, even if these
  hide the fact behind a slightly different syntax. The identical
  situation can reproduced in Scheme, in a slightly clearer way. This
  time I chose Pascal instead of Scheme because Scheme is less familiar
  to most people. I could not choose C because nested procedures are
  essential to the effect, as only with nested (lexical) procedure
  scopes we can generate the right sort of closure.

* Having objects be procedure instances and classes be procedures has
  the unfortunate effect of being constrained by the nested scope
  properties of procedures in conventional languages. This results in
  difficulties with non hierarchical program structures: not by chance
  the seminal paper on the OO decomposition paradigm by Dahl an Hoare
  has title "Hierarchical Program Structures". After CLOS I think it it
  is apparent (to me at least) that getting to OO via the more direct
  overloading route is more flexible, as overloading can be made to
  depend on multiple parameters, not just on that of the procedure
  instance.

Finally, I hope that the readers of this newsgroup (those who haven't
already read them) will run, not walk, to the nearest bookshop (not the
library: you want your very own copy to read at leisure) to get a copy
of "Structured Programming" and "Structure and Intepretation of Computer
Programs" (no, I don't get a commission on the sale of these books).

Learned quote of the month: "[I can vaguely recall seeing closures
equated to blocks, somewhere]". SICP, SICP, bless this soul! :-)
--
Piercarlo Grandi <pcg@aber.ac.uk> c/o Dept of CS
University of Wales, Penglais, Aberystwyth SY23 3BZ, UK
Newsgroups: comp.object