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

two questions: assignment to slots, and mixins with state



Hi, I just joined the self-interest list.  I've just started to get
familiar with Self, and have a few questions about style and general
Self idioms.  Bay says there's no FAQ, and I'm too lazy to go pore
through archives, so pardon me if these have been discussed before.
Also bear with me if my coding style is atrocious, but I haven't really
seen many smallish examples of every-day code (as opposed to all the
.sm files).

Suppose I have an assignable slot x:

_AddSlots: (| x <- 3 |)

I use x to retrieve the value of the slot, and x: to assign to it.
Now what if I want to keep track of the number of times x has been
assigned to?  I can add a new slot that gets incremented every time x:
gets invoked:

_AddSlots: (| numAssigns <- 0 |)

Now how do I define x: ?  If I do:

_AddSlots: (| x: newx = ( numAssigns: (numAssigns + 1) ) |)

the x slot never gets the new value.  If I do:

_AddSlots: (| x: newx = ( numAssigns: (numAssigns + 1).
    	    	    	  x: newx )
    	    |)

it recurses infinitely.  I've tried a bunch of other ways to assign to
x without using x:, but none of them work.  I can define a new slot to
hold the actual data:

_AddSlots: (| _ theRealX <- 3.
    	        x = ( theRealX ).
    	        x: newx = ( numAssigns: (numAssigns + 1).
    	    	    	    theRealX: newx )
    	    |)

but this seems kinda lame.  Am I missing some bit of syntax to assign
to a slot, or is there some other easy way of doing this?

----

My other question has to do with mixins.  Is there a typical way to
implement a mixin that has state?  Say I want to make a mixin for an
accumulator:

mixins _AddSlotsIfAbsent: (| accumulates = () |)
mixins accumulates _Define: (|
    ^_ accumulator <- 0.
       inc = ( accumulator: accumulator + 1 ).
|)

globals _AddSlotsIfAbsent: (| accumulatingPoint = () |)
accumulatingPoint _Define: (|
    parent* = traits point.
    accumulating* = mixins accumulates.
|)

Now the problem is that this state is shared among all instances:

_AddSlots: (| foo. bar |)
foo: accumulatingPoint clone
bar: accumulatingPoint clone


Self 77> foo accumulator
0
Self 78> bar accumulator
0
Self 79> foo inc
<object 136>
Self 80> foo accumulator
1
Self 81> bar accumulator
1

Now, I can move the accumulator slot to accumulatingPoint:

mixins accumulates _Define: (|
       inc = ( accumulator: accumulator + 1 ).
|)

accumulatingPoint _AddSlotsIfAbsent: (|
    ^_ accumulator <- 0.
|)

but this means that each object that wants to accumulate has to know
that it needs to define an accumulator slot, as well as define the
mixin parent slot.  There are two ways I've thought of to improve on
this: define a clone method on mixins accumulates, and have it add the
accumulator slot, followed by a resend; or define an
accumulatesPrototype object that defined the accumulator slot, having
each object that wants to accumulate have an additional data parent
slot that points to a clone of the accumulatesPrototype.  The former
solution would probably require that all the mixin parent slots have
different priorities or something, which are all higher than the
normal parent slots; this doesn't really seem workable.  The latter is
similar to the filledPolygon example in figure 3 of the "Organizing
Programs Without Classes" paper, but it involves having each instance
be a number of objects, instead of just one, and this seems clumsy
too.  Are there commonly used techniques to deal with this situation?
I guess this problem doesn't apply just to mixins, but this problem
came up when I was defining a mixin.

--

Sorry if this doesn't make much sense.  I'm just starting to get my
bearings with respect to Self coding and object design.  Thanks for
any help.

--Doug Orleans
dougo@pure.com