On Thu, 31 Aug 1995 00:03:54 +0200,
rainer(a)physik3.gwdg.de (Rainer Blome) wrote;
>imagine doing assignment another way. assignment is a hack (from the
>functional point of view). it manipulates its context. one should make
>that explicit by revealing the reflection involved in assignment. first
>get an object that represents the place (the slot). that is the reflective
>part. then send it a normal message with the new value as an argument:
>(reflect: self slot: "x") store: 1
On Wed, 30 Aug 1995 16:26:55 -0700,
ungar@self (David Ungar) wrote:
> We have had lots of discussions about
> assignment, but what it boils down to for me is
> that containers are appealingly intuitive notion,
> and so I am happy to ground out where it does.
> Going deeper does not seem to me to buy so much.
Here is who I did it in tinySelf: every slot in a map has a name,
a value and a "type". The type is actually just a pointer to some
code that gets called with the value as an argument. Right now
this field points to C functions, but it would point to pre-compiled
Self code in the future, allowing the user to create new slot
types. Currently, these are the types that are avaiable:
- constant: this code simply pushes the value on the stack
- data: this code pushed *(self+value) on the stack
- assignment: this code pops the stack and stores it in *(self+value)
- code: this calls the interpreter with value, which is a method
When I write the compiler later, it could simply replace the pointer
to the interpreter in "type" by a pointer to the newly generated code
( which would ignore "value", of course ). I won't do it this way,
but the main idea it that "compiled code", "primitives" and the
"assignment primitives" should all be made from the same stuff.
On Mon, 15 Oct 90 14:40:43 PDT ( note the date - I have a good memory ;-),
ungar@thoreau (David Ungar) wrote:
> 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.
I am not very happy with my solution of slot types, but I don't expect
it to break any existing code. It is true that if you store a method
object into a data slot, it will *not* be executed when you try to
fetch it. But I don't think it is even possible to store a method in
a data slot in Self 4.0, is it?
It is strange how close assignment is to argument initialization -
(| x |) x: 9
[| :x | ... ] value: 9
I used a block in this example to ignore the cloning that goes on in
the argument initialization. The difference is that arguments are
initialized by the *position* while the assignment works by *name*.
Beta almost managed to unify these two notions, but didn't quite
manage it. BTW, the more I learn Beta, the more I like Self!
( though I did find Beta much more fun than Oberon or C++ )