Fwd: Question about Reaction behaviour

5 views
Skip to first unread message

Edwin

unread,
Aug 26, 2009, 3:50:29 PM8/26/09
to Sergey Schetinin, better...@googlegroups.com
Hi Sergey,

I have tried to write a small demo script and when running ( in CPython this time, to rule out possible Jython quirks ) I get some unexpected results that I were hoping you could comment on.

The script:

from mext.reaction import *

@atomic
def init(container):

a = A()
a.Id = "a"
container.add(a)
b = A()
b.Id = "b"
container.add(b)
b.previous = a
c = A()
c.Id = "c"
container.add(c)
c.previous = b

class A(Component):
attrs (
Id = "",
size = 3,
space = 5,
previous = None,
left = -1,
right = 999,
)

@maintain
def SetLeft(self):
value = 0
if self.previous:
value = self.previous.right + self.space
self.left = value

@maintain
def SetRight(self):
self.right = self.left + self.size

def __repr__(self):
value = "%r: [%r,%r]" % (self.Id, self.left, self.right)
if self.previous:
value += " p=%r" % (self.previous.Id)
return value

cont = set()
init(cont)

for a in cont:
print a

The output that I would expect is:

'a': [0,3]
'b': [8,11] p='a'
'c': [16,19] p='b'

There are however two problems: 
1. When repeatedly running the script, the results are not constant 
2. The output is unexpected and not equal to the above expectation ( two possibilities on my machine ):

'a': [0,3]
'b': [8,3] p='a'
'c': [8,11] p='b'

'a': [0,3]
'b': [8,3] p='a'
'c': [8,3] p='b'

It seems to me that, likely due to some error in my script, the @maintain functions are not reactivated correctly or in the wrong order. What am I doing wrong ?

Thank you for any help you can give me.

Best regards,
Edwin

Sergey Schetinin

unread,
Sep 10, 2009, 3:23:51 AM9/10/09
to Edwin, better...@googlegroups.com
Hi,
Sorry for the delay.

The problem is caused by special status of initialization and how it
plays with circularity / wrong order detection. Reimplementing it is
on top of my list for Reaction, but I can't tell you when will I get
to work on it again. Maybe later this month, maybe in October.

http://code.google.com/p/trellis-fork/issues/detail?id=5

Anyway, this problem only matters for @maintain rules and I didn't
write the new docs yet, but one of the things I wanted to explain
there is that for cleaner, easy-to-understand and safe code one should
avoid @maintain as much as possible, whenever possible, opt for
readonly rules (@compute and @track). It's also true for Trellis, but
I specifically worked to make Reaction guide to that kind of design.
For your example that would mean the following changes:

* first of all, replace SetRight w/ a compute rule:

class A(Component):
attrs (
Id = "",
size = 3,
space = 5,
previous = None,
left = -1,

)

@maintain
def SetLeft(self):
value = 0
if self.previous:
value = self.previous.right + self.space
self.left = value

@compute
def right(self):
return self.left + self.size

def __repr__(self):
value = "%r: [%r,%r]" % (self.Id, self.left, self.right)
if self.previous:
value += " p=%r" % (self.previous.Id)
return value


If you try that edit, you'll see that the problem is gone.

* SetLeft should be replaced w/ a compute rule as well, but it might
not be obvious how to do it -- it should be settable. That's why
reaction.compute has a (write=) arg

class A(Component):
attrs (
Id = "",
size = 3,
space = 5,
previous = None,

_left = 0,
)

@compute(write_to='_left')
def left(self):
if self.previous:
return self.previous.right + self.space
else:
return self._left

@compute
def right(self):
return self.left + self.size

def __repr__(self):
value = "%r: [%r,%r]" % (self.Id, self.left, self.right)
if self.previous:
value += " p=%r" % (self.previous.Id)
return value

One could go further and make sure .left is not settable when
.previous is not None or do the Coherence-like thing and change
.previous.left in such cases, but I'll stop here.


Anyway, the problem is a known bug and (unless I'm really confused)
inherited from Trellis. I do know how to fix it (it will go away
magically after init system is rewritten in a certain way), but you
still shouldn't be using @maintains in that way.

-Sergey


2009/8/26 Edwin <edwind...@gmail.com>:

--
Best Regards,
Sergey Schetinin

http://s3bk.com/ -- S3 Backup
http://word-to-html.com/ -- Word to HTML Converter

Edwin

unread,
Sep 10, 2009, 4:54:49 AM9/10/09
to Sergey Schetinin, better...@googlegroups.com
Hi Sergey,

Thank you for your answer!

I will try out the different possibilities you have suggested and I will try to understand and digest your thoughts about best practices and why and how it should work. 

I was however triggered by your last remark about Trellis. I have 'transcribed' the same script to a Trellis script. In Trellis however it does seem to work exactly like I had expected:

>python repro2.py
'a': [0,3]
'b': [8,11] p='a'
'c': [16,19] p='b'

Source:

from peak.events import trellis

@trellis.modifier
def init(container):
a = A()
a.Id = "a"
container.add(a)
b = A()
b.Id = "b"
container.add(b)
b.previous = a
c = A()
c.Id = "c"
container.add(c)
c.previous = b
class A(trellis.Component):
trellis.attrs (
Id = "",
size = 3,
space = 5,
previous = None,
left = -1,
right = 999,
)

@trellis.maintain
def SetLeft(self):
value = 0
if self.previous:
value = self.previous.right + self.space
self.left = value
@trellis.maintain
def SetRight(self):
self.right = self.left + self.size
def __repr__(self):
value = "%r: [%r,%r]" % (self.Id, self.left, self.right)
if self.previous:
value += " p=%r" % (self.previous.Id)
return value
cont = set()
init(cont)

for a in cont:
print a




Sergey Schetinin

unread,
Sep 10, 2009, 5:29:34 AM9/10/09
to Edwin, better...@googlegroups.com
Try adding

def __init__(self):
self.SetRight
self.SetLeft

to A -- I believe the correct result you get w/ Trellis is just luck
-- this __init__ will force the initial incorrect order and unless
Trellis does handle that it will have the same problem.

2009/9/10 Edwin <edwind...@gmail.com>:

Sergey Schetinin

unread,
Sep 10, 2009, 5:55:22 AM9/10/09
to Edwin, better...@googlegroups.com
It does seem to handle it, I'll look into it.

2009/9/10 Sergey Schetinin <mal...@gmail.com>:

Sergey Schetinin

unread,
Sep 10, 2009, 6:55:29 AM9/10/09
to Edwin, better...@googlegroups.com
OK, here's a fix + test:
http://code.google.com/p/trellis-fork/source/detail?r=263

I was wrong when saying that it would fail in the same way w/ Trellis,
but it is actually init-related. There are a few init-related issues
w/ Trellis and some of them fixed in Reaction, some of them not (you
can find them in tests/ dir).

A few more things, for some reason copy-pasting code from your emails
looses all the indentation and text-version of them is kinda garbled,
please try to make sure you send messages in text-format so that code
indentation is OK.

Also, you might be interested in a more idiomatic version of your code:


from __future__ import with_statement
from mext.reaction import *

class A(Component):
attrs(


Id = "",
size = 3,
space = 5,
previous = None,
left = -1,
right = 999,
)
@maintain
def SetLeft(self):
value = 0
if self.previous:
value = self.previous.right + self.space
self.left = value

@maintain
def SetRight(self):
self.right = self.left + self.size

def __repr__(self):
value = "%r: [%r,%r]" % (self.Id, self.left, self.right)
if self.previous:
value += " p=%r" % (self.previous.Id)
return value

with ctrl.new_txn():
a = A(Id='a')
b = A(Id='b', previous=a)
c = A(Id='c')
c.previous = b
#print '---'
#print get_cell(a, 'right') in list(get_cell(b, 'SetLeft').iter_subjects())
#print get_cell(b, 'SetLeft') in list(get_cell(a, 'right').iter_listeners())


print a
print b
print c

#print list(get_cell(b, 'SetLeft').iter_subjects())
#print list(get_cell(c, 'SetRight').iter_subjects())


2009/9/10 Sergey Schetinin <mal...@gmail.com>:

Reply all
Reply to author
Forward
0 new messages