Single changes in state and sets of changes

5 views
Skip to first unread message

Kaste

unread,
Nov 20, 2010, 7:37:58 AM11/20/10
to Better Python
Ok, hi to all.

Using reaction for about 2 hours, ran into the following.

Say I have a web of objects, or cells. I have set up the basic
functionality so when I change the state of one object, some of the
other objects get automatically notified. This is very convenient.
From outside the rules on an interactive session and in the unittest,
every object has always the state I expect.

Now I need a side-effect. After or during a recalculation sweep, all
changed cells needs to inform (send a message to) a 'writer' with say
(old_val, new_val). (Actually each cell already has a string
representation, which is all i would need.) This writer/object must
perform on the complete set of changes. It cannot act upon each
message he gets. Instead he has to wait until the recalculation of all
cells is done. It has to perform the action once per recalculation, so
to speak. (There is no performance reason for this, I really have to
alter this change-set.)

How can I do this?

I think we could also think of a GUI. When I move one element some
other elements move away. But the elements don't actually draw
themself, because they just don't now how to draw a pixel. Then I have
a writer/viewer that actually gets the message (move, from, to). In my
case it is not sufficient just to redraw all the elements on their new
position, I need their old position. Maybe to delete/reset the old
pixel-representation.

So how do we mess with changing state, i.e. from old_val to new_val?
And how can I think about the problem of change 'sets'.

Regards
kaste


Sergey Schetinin

unread,
Nov 20, 2010, 8:13:06 AM11/20/10
to better...@googlegroups.com
Hi,
I considered adding adding a 'read_prev' method to cells and a
matching function for the Components ( read_prev(ob, 'cellname') ),
but never got to it. While the transaction is running, you can get the
old value by reading ctrl.txn.snapshot[cell.key].

Processing a whole lot of changes at once is quite difficult as it is,
so I'll describe how it *should* work. Right now there are a couple of
queues for actions to execute once the transaction is done -- effects
(everything is called in the same txn), pure effects (w/ disabled txn)
and no-txn (called outside of txn, so the callbacks can initiate their
own txns). This is a bit messy and should be generalized by allowing
the client code to create their own queues and then process them on
their own. For your use case you would create a queue to group all
these changes and put the change notifications in it (not callbacks),
the queue processor would go over them getting the entire picture and
then acting on it. There's no support for this in Reaction yet, but
this is doable without that support.

Then there's a problem of noting all those changes and adding them to
the queue / changeset. I'm not sure how much your cells that need to
be a part of this vary, but I would probably go for subclassing the
cell implementation so that the cell itself adds the change to the
queue. Observing cells from the outside would require an observer per
cell which could be inefficient. Having just one observer for all of
them could work, but only if almost all of cells change together and
you'll need to find which cells have changed yourself (looking at the
ctrl.txn.writes).

Another option to consider (but very carefully) is that maybe you can
do that by subclassing the transaction itself and processing the
changes in the commit phase -- you're guaranteed to have a very
complete view of everything that happened in a txn.

All of this is pretty hardcore, and I would recommend trying to read
and understand the implementation first. In particular this could get
you started (if you haven't read it already):
http://self.maluke.com/txns

-Sergey

> --
> Mailing list: http://groups.google.com/group/better-python
> Unsubscribe: better-pytho...@googlegroups.com

--
Best Regards,
Sergey Schetinin

http://self.maluke.com/ -- My articles and open-source stuff
http://www.maluke.com/ -- My commercial software and custom development services

Kaste

unread,
Nov 21, 2010, 12:49:51 PM11/21/10
to Better Python
Actually that's way ahead of me. I basically set up this as an
example:

http://dpaste.de/RIOA/

It's a clone of this trellis code:

http://dpaste.de/dKKb/

As you can see with reaction I need two additional, private
attributes.
One of them is because trellis' maintain lets me access the old
value.

After all it seems trellis' perform is your maintain, and trellis'
maintain is just gone.
compute is compute after all, but has a nice 'write_to' functionality.

What I was thinking: Since each cell knows its own changes, I inject a
writer-obj into each cell, and let the cell notify the writer about
its changes. The changes are written to a todo-attribute. The writer
would then act upon this todo-list, hopefully once per recalculation
sweep.

Some comments:

1.

> ctrl.txn.snapshot[cell.key]

clearly no idea, what the heck??. I know I could do a 'with
ctrl.new_txn()' from outside the rules/cells, that is: do a couple of
things atomically, but ... snapshot, cell.key , no idea

2.

I see effect and pure_effect, but no no-txn. That should be
after_txn ?

3.

Please do some docstrings. At least to all decorators. And at least
one interactive walkthough (tutorial).

Regards
Kaste
> http://self.maluke.com/-- My articles and open-source stuffhttp://www.maluke.com/-- My commercial software and custom development services

Sergey Schetinin

unread,
Nov 21, 2010, 4:00:46 PM11/21/10
to better...@googlegroups.com
On 21 November 2010 19:49, Kaste <herr....@googlemail.com> wrote:
> Actually that's way ahead of me. I basically set up this as an
> example:
>
> http://dpaste.de/RIOA/

self.children.append(child) is very wrong. Use `self.children =
self.children + [child]` or something of that kind -- even
`self.children += ...` is no good because the attribute has to be set
to a new object for the change to be noticed. Also these things are
usually better implemented as @track rules that take the new items
from some resetting attribute.

@todo / future support was also very recently removed from Reaction,
it was too messy and should be implemented as described above.

> It's a clone of this trellis code:
>
> http://dpaste.de/dKKb/
>
> As you can see with reaction I need two additional, private
> attributes.
> One of them is because trellis' maintain lets me access the old
> value.

Reaction @track allows that as well but in a much cleaner fashion, for example:

@track
# or @track(writeable=True)
def rule(self, oldval):
return self.other or oldval


> After all it seems trellis' perform is your maintain, and trellis'
> maintain is just gone.
> compute is compute after all, but has a nice 'write_to' functionality.

The Trellis @perform is actually pretty broken -- it is intended for
effects but runs inside the transaction and can make it fail and its
effects are not rolled back. It also cannot see resetting / discrete
values. I also remember there were sometimes problems when things are
first touched from @perform and cause a cell initialization, can't
remember exactly what the problem was.

Reaction @maintain is kind of like Trellis' @maintain, but has no
value, because a cell that has a value but also can write other cells
causes a huge mess. So if you want a non-lazy value that can also
access its previous value, use @track (but remember that it cannot
have effects). Trust me this separation was a very good idea.

All side effects should be done via effect(...) or similar. There's
also an @effect_method helper for that. The effects can only be added
from @maintain rules and from @atomic / `with new_txn`.


> What I was thinking: Since each cell knows its own changes, I inject a
> writer-obj into each cell, and let the cell notify the writer about
> its changes. The changes are written to a todo-attribute. The writer
> would then act upon this todo-list, hopefully once per recalculation
> sweep.

That a reasonable way to do it. @todo is gone though, but you can do
the part you need yourself. For example see EventQueue.call /
_call_queue implementation in the repo tip. Instead of scheduling a
dependent cell you can just add an effect to process the queue you're
building.

> Some comments:
>
> 1.
>
>>  ctrl.txn.snapshot[cell.key]
>
> clearly no idea, what the heck??. I know I could do a 'with
> ctrl.new_txn()' from outside the rules/cells, that is: do a couple of
> things atomically, but ... snapshot, cell.key , no idea

Well, when the transaction runs the ctrl.txn is set to current
transaction (None otherwise). You can also do this:

with ctrl.new_txn() as txn:
# here txn is the same as ctrl.txn

The cell values are not stored in cells themselves, they are stored in
the snapshots / transaction. So when you read a cell outside of a
transaction you read a value from the current snapshot. That snapshot
is a dictionary. And the keys in that dictionary are objects that are
stored as cell.key for every cell. You can get the cell object from a
component by calling get_cell(ob, 'attr_name').

So when the transaction starts it has to keep the old values, so it
keeps the snapshot as txn.snapshot and the writes go either to
txn.writes or to txn.transient. When the transaction commits Reaction
copies the snapshot and does new_snapshot.update(writes).

So for as long as transaction runs all the pre-txn values are
accessible via that snapshot dictionary.

Try reading some implementations from mext.reaction.celltypes, it
should make things a bit more clear.

> 2.
>
> I see effect and pure_effect, but no no-txn. That should be
> after_txn ?

Yep. See also mext.reaction.stm.transactions:EffectsMixin

> 3.
>
> Please do some docstrings. At least to all decorators. And at least
> one interactive walkthough (tutorial).

Well, there's generally very little interest in all of this stuff and
it's just too hard for most programmers. Plus I don't have much spare
time at the moment. But yeah, eventually I'll do it.

Regards,
Sergey

http://self.maluke.com/ -- My articles and open-source stuff
http://www.maluke.com/ -- My commercial software and custom development services

Reply all
Reply to author
Forward
0 new messages