Thursday, August 5, 2010

RPython Part2

There are at least two cases where runtime variables can be problematic in RPython with subclasses that have methods with the same name, and 1. return different types, or 2. like-named methods taking different number of arguments - in other words having a different signature. The solution requires not only a if/else block, but also a assert statement that proves type. Note that proving the type in the container's get function is of no help. If the variable outside is known and concrete at translation time then everything works, if however it is passed in from CPython (as it is here) or read from a pipe or socket it is no longer concrete and translation fails.



class T(object): pass

class TA( T ):
def whoami(self): print 'i am instance of TA'
def incompatible_return( self ): return 100
def diff_args( self, a,b,c ): print 'TA: ', a, b, c
def diff_num_args( self, a,b ): print 'TA: ', a, b

class TB( T ):
def whoami(self): print 'i am instance of TB'
def incompatible_return(self): return 'string'
def diff_args( self, x='1', y='y', z='z' ): print 'TB: ', x, y, z
def diff_num_args( self, a,b,c ): print 'TA: ', a, b, c

class Container(object):
def __init__(self, *args):
self.items = []
for item in list(args): self.items.append( item )
def get( self, index ):
a = self.items[index]
if index==0:
assert isinstance(a, TA)
return a, TA
else:
assert isinstance(a, TB)
return a, TB

#File "pypy/pypy/translator/c/node.py", line 998, in _python_c_name
# Exception: don't know how to simply render py object: 100
def entrypoint_incompatible_fails( outside ):
ta = TA()
tb = TB()
con = Container( ta, tb )
a,klass = con.get(outside)
assert isinstance(a, klass) # too bad this wont work
b = a.incompatible_return()
print b

## this works, so SomeObject subclasses method calls are fine as long as the number of args it the same and the return is the same type.
def entrypoint_diffargs_works( outside ):
ta = TA()
tb = TB()
con = Container( ta, tb )
a,klass = con.get(outside)
a.diff_args( 1,2,3 )
a.whoami()

## assert is required ##
def entrypoint_branching_fails( outside ):
ta = TA()
tb = TB()
con = Container( ta, tb )
a,klass = con.get(outside)
if a.__class__ is TA:
a.diff_num_args( 1,2 )
elif a.__class__ is TB:
a.diff_num_args( 1,2,3 )


def entrypoint_branching_works( outside ):
ta = TA()
tb = TB()
con = Container( ta, tb )
a,klass = con.get(outside)
if a.__class__ is TA:
assert isinstance( a, TA ) # this is required
a.diff_num_args( 1,2 )
elif a.__class__ is TB:
assert isinstance( a, TB ) # this is required
a.diff_num_args( 1,2,3 )


PATH2PYPY = 'pypy'
sys.path.append(PATH2PYPY) # assumes you have pypy dist in a subfolder, you may need to rename this pypy-trunk

def tests( outside ):
entrypoint_branching_works(outside)

from pypy.translator.interactive import Translation
t = Translation( tests )
t.annotate([int]); t.rtype()
f = t.compile_c()
f(0)
f(1)
print( 'end of program' )

No comments:

Post a Comment