simple object model (was: [self-interest] selfing Self)

Jecel Assumpcao Jr jecel at merlintec.com
Fri Mar 30 19:59:09 UTC 2001


I am sending a copy of this to the self-interest list. I hope you don't 
mind.

On Friday 30 March 2001 04:39, Uladzimir Liashkevich wrote:
> Let me join the discussion. This is a very interesting topic to me.
> When I first read about Smalltalk I thought that it is the greatest
> language ever. Then I discovered some difficulties with the language,
> for example absense of multiple inharitance causes strange
> inharitance trees like Object -> ReadStream -> ReadWriteStream.

My favorite example is String, which can't decide if it should be a 
Magnitude or a Collection...

> When I read about Self, I felt the same as in the case of Smalltalk.
> Later I discovered the absense of some needful possibilities. One of
> them is constructing objects on the fly. One cannot write something
> like this: (| x:Y: = (| :aX. :aY | ^(| x <- aX. y <- aY |) ) |).

While this doesn't work because slot initializers ("aX" and "aY" in 
this case) are always evaluated in the context of the lobby object, you 
can get the same results with:

     (| x:Y: = (| :aX. :aY. new |
            new: (| x. y. parent* = traits clonable |) copy.
            new x: aX.
            new y: aY.
            new)
     |)

The reason I used 'copy' above is that I am supposing that you don't 
want successive calls to this method to always return the exact same 
object, but just the same kind of object. If that is the case but you 
don't want the new object to be clonable, we could use the '_Clone' 
primitive instead of 'copy' and eliminate 'parent*'.

If you wanted 'x' and 'y' to be constant slots in the new object (you 
didn't show that in your example) then things do get much more 
complicated. It is still possible to do this using mirrors, however.

But I was indeed trying to make this kind of thing simpler.

> So
> now I'm in process of thinking out a more flexible but yet powerful
> language. By now I have implemented two experimental versions of
> Self. But I need something different.

Me too, but more in the spirit of Self than the Self-inspired languages 
of the early 1990s.

> > Like a simple object model: objects are just flat association lists
> > (I'll use Lisp notation below) -
> >
> >        (x 3 y 4)
>
> flat list has an array structure rather than linked list?

By "flat" I meant compared to this form of association list:

  ((x 3) (y 4))

But it is a *very* interesting question if these should be arrays or 
linked lists -

  Lists: + can be shared as the continuation (CDR) of several other     
               lists
            + can be scanned using a single pointer
            - since you can point into the "middle" of a list there are 
                many aliasing problems
            - can't be indexed into
            + can be as space efficient as arrays with special encoding
            + easy to split and put together

   Arrays: - need three items for scanning: base, index and size
                + no need to waste more than one virtual address per    
                   array
                + access to any element is equally fast

It is easy to convert one into the other when you need to do some kind 
of processing for which the normal format is not very good.

> Do you want to use the same semantics for a objects, arrays and
> hashes? Like, (1 2 3) - array, (x 3 y 4) - object or hash?
> Please describe that semantics a bit more.

Every object is a list, but there are lists which are not formatted 
objects (the code examples below, for instance). So I must treat (1 2 
3) as an object which does not explicitly list the messages it 
understands. In fact, the object "1" has this problem as well, but at 
least the number objects have special tags so they don't look like they 
might be a regular object. I am still figuring this out.

> >     append '(z 9) '(x 3 y 4)
>
> Is this a message-sending construction? What is the receiver?

No, this was a pseudo Lisp functional notation. This would be more 
proper

   '(z 9) append: '(x 3 y 4)

though the problem above shows itself here: how does the '(z 9) object 
understand the 'append:' message? We would have to force it to be 
treated as a plain list, which is getting into the reflective level and 
similar to requesting a mirror for an object in Self.

This needs some careful design.

> How to distinguish objects and methods?

I am thinking of making methods internally be objects that have a 
special <code> "slot"

 ... factorial: (n 0
                     <code> (n < 1 ifTrue:False: 1 '(n * factorial: n-1)
                                   )
                    ) ....

I have other ideas for blocks than quoted lists, but this will do for 
now. Hmmm... if instead of "<code>" I used "|" then this would look 
more like Smalltalk...

Note that though the argument "n" has a default value of 0, it will be 
replaced once this code object is cloned to create a context object.

> Did you get rid off keyworded selectors like a:B:C:?

I used one in the above example, but at the low level the keywords 
aren't spread among the arguments. In a higher level graphical editor I 
would expect you to be able to write something like

    n < 1 ifTrue: 1 False: [n * factorial: n - 1]

My idea is that the arguments would be underlined, but that is hard to 
show using ASCII in this email.

> > [these nested lists can act as both "maps" and parents]
>
> Really good fresh idea.
> It seems that all slots are assignable, doesn't it?

That is something to be fixed. The implemenation must be able to tell 
what is changable and what is (normally, at least) constant. In the 
NeoLogo implemenation where these ideas came from you could write

  make "x 10

and simply change the value of the x "slot". It would be better to do 
the same thing by sending a message instead

  x: 10

and you could have the Self rule that unless there is a "x:" method 
then "x" is a constant slot. I don't know what the best way to handle 
assignments is. I have always felt that assignments and argument 
replacement should be somehow related. Kyle doesn't like the fact that 
assignment slots must be in the same objects as their data slots in 
Self (they can't be moved into the parent objects, for example).

> The first challenge is to invent such system, then it can be
> optimized. Remember that many people doubted that Self can be
> implemented efficiently...

Right, we can always hope that history will repeat itself. On the other 
hand, there are many examples of interesting ideas that nobody ever 
figured out how to do reasonably well. Dynamic parent slots in Self are 
an example (actually, I did figure out a way to do it but haven't tried 
it yet).

-- Jecel



More information about the Self-interest mailing list