Derived class doesn't inherit some magic(dunder) methods from the parent class
The user-defined functions are inherited as expected , but overriden dunder methods like __str__() or __mul__() or __rmul_()_are not. Whereas __le__() , __lt__(), __eq__() works
class stu:
def __init__(self,phy=0):
self.phy=phy
def __str__(self):
return "testing"
def test(self):
print("user defined methods working")
def __mul__(self,x):
print("working ", x)
class cstu(stu):
def __init__(self,phy=0,math=0):
stu.__init__(self,phy)
self.math=math
a = cstu(30)
print(a)
a.test()
a*4
this gives me the expected output in python
testing
user defined methods working
working 4
while in voc i get,
<cstu object at 0x621be5d1>
user defined methods working
Exception in thread "main" TypeError: unsupported operand type(s) for *: 'cstu' and 'int'
at org.python.types.Object.__mul__(Object.java:566)
at python.inher.__init__.module$import(inher.py:39)
at python.inher.__init__.main(inher.py)
Confirmed here.
This is so because in Java cstu inherits from org.python.types.Object, not from stu, and the * operator calls __mul__ on that cstu object, which is resolved to org.python.types.Object.__mul__.
As @cflee has mentioned in #363, one way to make it right is to getattribute and do Callable.invoke, and this should be the most straightforward solution.
And I just came up with another solution: how about making all the dunder methods delegates i.e. By leveraging Strategy Pattern? I guess this would avoid the getattribute and Callable.invoke, so as to boost performance and reduce generated code size (well, with static method helpers we won't worry about code size, though: #363).
This solution would require a major reorg of current code and need some serious discussion, IMHO.
What do you think? @cflee @freakboy3742 @eliasdorneles
@eliasdorneles How about, whenever voc encounters a binop method , we convert it into a call node and pass it to the visit_Call() where it will be processed accordingly? I modified the visit_BinOp() ast.py file (this is just a test modification) :-
def visit_BinOp(self, node):
# expr left, operator op, expr right):
#print(node.left.ctx)
if isinstance(node.op, ast.Pow):
self.visit(node.left)
self.visit(node.right)
self.context.add_opcodes(
JavaOpcodes.ACONST_NULL(),
JavaOpcodes.INVOKEINTERFACE(
'org/python/Object',
'__pow__',
args=['Lorg/python/Object;', 'Lorg/python/Object;'],
returns='Lorg/python/Object;'
),
)
elif isinstance(node.left,ast.Name): #this is the part that i added
self.visit(node.left)
self.visit(node.right)
attr2 = ast.Attribute(value=node.left,attr="__mul__",ctx=ast.Load())
node.func = attr2
node.args = [node.right]
node.keywords = []
self.visit_Call(node)
print("passed to visit_call")
return ####
else:
self.visit(node.left)
self.visit(node.right)
self.context.add_opcodes(
JavaOpcodes.INVOKEINTERFACE(
....
this is the test example:-
class stu:
def __init__(self,phy=0):
self.phy=phy
def __str__(self):
return "testing"
def test(self):
print("user defined methods working")
def __mul__(self,x):
print("working ", x)
class cstu(stu):
def __init__(self,phy=0):
stu.__init__(self,phy)
a = cstu(30)
print(a)
a.test()
a*4
this gives the correct output for the __mul__() in voc after the modification:-
<cstu object at 0x4ee285c6>
user defined methods working
mul working 4
I am still working on the print method.