Having trouble making a simple recursive inspector.

David Ungar ungar at thoreau
Mon Oct 15 21:40:43 UTC 1990

	From clp at parian.bos.marble.com Mon Oct 15 12:00:24 1990
	Return-Path: <clp at parian.bos.marble.com>
	To: self-interest at self.stanford.edu, clp at parian.bos.marble.com
	Subject: Having trouble making a simple recursive inspector.
	Cc: alex at xait.xerox.com
	Status: R

	I tried to create a simple recursive inspector just to see if I could.

	After a little fiddling I came up with:

	_AddSlots: (| irec: = (| :obj m. | m: obj _Mirror. inspect: obj.
		m _MirrorSize do:
			[|:n| irec: (m _MirrorContentsAt: n) _MirrorReflectee].)|)

	Which is called, e.g., via "irec: <an object>" like the normal inspect:

	Now I know that even is this did run, it would probably run forever due to
	 loops in the system structure, but I want to watch it run through the parent
	 pointer, etc.

	It seems to work just fine except that methods won't respond to _MirrorReflectee
	 for some reason (Grrrr!!).  This seems like a needless non-generality!  Am I
	 missing something?  Why can't methods allow this?  Is there an equally simple
	 (or any easy) way to do what I want?

Bay's reply summed it up nicely, but I thought I would add my own $0.02 worth:
First, I am VERY glad you are writing Self programs!
Keep it up!

Now the explanation:

We believe strongly in the benefits of reusing the same code with different representations.
This implies that the code may not distinguish between reading a variable and invoking a function.
How to model this in a programming language?
One way would have been to have different kinds of slots: data slots and code slots.
Had we done this we could have had functions which only evaluated when fetched out of a code slot.
We rejected this approach on two grounds:
	1. clutter caused by multiple slot types
	2. functions considered harmfull.
		In OOP a receiver gets to decide what code to run. But if you have functions
		they always do the same thing no matter what the objects are.
		I believe that functions perniciously weaken the power of data abstraction by
		taking control away from the objects, and by packaging up code without data.
So, we opted for one slot type, and a model that says that an object is always executed
when fetched from a slot. Most objects simply return themselves when they execute.
As a result, you cannot have a naked method in Self, because it would have run when you fetched
it, and you would have gotten the result of the method.
So, we have mirrors. A mirror is a way to handle an object without evaluating it,
much like a "ten foot pole". When doing reflective computation (as your example does)
always stick with mirrors.


PS Is this in any of the papers? Should we write something on self-reflection some day?

More information about the Self-interest mailing list