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