[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

assignment (was: macros / code construction)



On Thu, 31 Aug 1995 00:03:54 +0200,
rainer@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
            object

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++ )

-- Jecel