-
Notifications
You must be signed in to change notification settings - Fork 164
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Class inheritance example #2800
Comments
Let's explore how to do it via an ASR -> ASR pass. For that, the input ASR is with methods with the virtual flag. The output ASR must have explicit virtual function table and calls into it. Let's first write an example that compiles today, that implements the above example. Roughly: # Base class
class A:
def myprint2():
print("A")
def myprint():
print("A")
def f(a: A):
a.myprint()
# subclass
class B(A):
def myprint():
print("B")
def main():
a: A = A()
b: B = B()
c: B = B()
f(a)
f(b)
f(c)
main() Output: # Base class
class A:
def __init__(self):
self.VMT = [Pointer to A.myprint2, Pointer to A.myprint]
def myprint2():
print("A")
def myprint():
print("A")
def f(a: A):
a.VMT[1](a)
# subclass
class B(A):
def __init__(self):
super(self).VMT = [Pointer to A.myprint2, Pointer to B.myprint]
def myprint():
print("B")
def main():
a: A = A()
b: B = B()
c: B = B()
f(a)
f(b)
f(c)
main() If this is not fully clear, then let's start with C. Implement the "Output" in C, with function pointers. |
Let's write this as an ASR->ASR pass that takes the "Input" above and converts it to the "Output" above. An ASR->ASR pass will be easy to debug, we just print it as Python or Fortran code and can easily see how the compiler implements the feature. This keeps the door open to later do a different ASR pass: that implements compile time polymorphism where the subclass is known. Also there might be other optimizations possible, since we implement all this at ASR level: for example all kinds of function inlining and other simplifications if we know things at compile time. Notes: later we can merge this ASR->ASR pass with the LLVM backend. This will speedup compilation, but it will make the backend more complex, so let's do that later, if we want to. It will make it harder to debug. It might also disallow some ASR optimizations, since we will only be implementing it in the backend. We can also consider merging this ASR->ASR pass with the frontend (with the AST->ASR pass), but that will mean we can't represent polymorphism in ASR directly at higher level, the AST->ASR would already lower this high level feature. And that means that it would close the door to later add compile time polymorphism for cases where the compiler knows the subclass. So I would not do that. |
We should implement runtime polymorphism, using virtual function tables. Here is the simplest example:
The function
f
accepts the base class and calls the virtual functionmyprint
. This will get fully compiled to ASR and to LLVM, without knowing any subclasses. Then later we call it like this:The call
f(a)
will print "A", the callf(b)
will print "B".Steps to get it implemented:
virtual
flag to ASR's methods. Mark every method asvirtual
in LPython.myprint
via the table in the functionf
a = A()
will create and populate the virtual function tableb
and another time forc
. Then later as an optimization we will share it.Note: the instances
c
andb
both share the same virtual function table. The compiler will create the virtual function table just once for the typeB
. Then all instances (b
andc
above) just have a pointer to this same (shared) table.To be figured out: it is not clear when this virtual function table is created. One option is at start time of the program. Another option is at the first instantiation of
B
intob
, and reused for the second instantiation (c
).The text was updated successfully, but these errors were encountered: