lpython icon indicating copy to clipboard operation
lpython copied to clipboard

Handle class constructor

Open Thirumalai-Shaktivel opened this issue 1 year ago • 13 comments
trafficstars

from lpython import i32

class test:
    y: i32 = 2
    def __init__(self, x: i32 = 1):
        self.x: i32 = x

t1: test = test()
t2: test = test(3)
print (t1.x)
print (t1.y)
print (t2.x)
print (t2.y)

I think we can skip the __init__() It has to be represented as a StructTypeConstructor, the class_constructor will take care of the rest.

Thirumalai-Shaktivel avatar Jun 12 '24 16:06 Thirumalai-Shaktivel

Assign: @tanay-man

Thirumalai-Shaktivel avatar Jun 12 '24 16:06 Thirumalai-Shaktivel

Let's do this.

from lpython import i32, TypeVar

test = TypeVar("test")
class test:
    x: i32 = 0
    y: i32 = 0
    def __init__(self: test, x: i32, y: i32):
        self.x: i32 = x
        self.y: i32 = y

# StrucTypeConstrutor(3, 3)

t2: test = test(3, 3)

Thirumalai-Shaktivel avatar Jun 12 '24 16:06 Thirumalai-Shaktivel

Another example:

from lpython import i32, TypeVar

test = TypeVar("test")
class test:
    kind: str = "abc"
    def __init__(self: test, name: str):
        self.name = name

t1: test = test("1")
t2: test = test("2")

print(t1.kind)
print(t2.kind)

t2.kind = "d"
print(t1.kind)
print(t2.kind)

print(t1.name)
print(t2.name)

Thirumalai-Shaktivel avatar Jun 12 '24 16:06 Thirumalai-Shaktivel

Instead of:

from lpython import i32, TypeVar

test = TypeVar("test")
class test:
    x: i32 = 0
    y: i32 = 0
    def __init__(self: test, x: i32, y: i32):
        self.x: i32 = x
        self.y: i32 = y

# StrucTypeConstrutor(3, 3)

t2: test = test(3, 3)

I recommend doing this:

from lpython import i32, TypeVar

test = TypeVar("test")
class test:
    def __init__(self: test, x: i32, y: i32):
        self.x: i32 = x
        self.y: i32 = y

# StrucTypeConstrutor(3, 3)

t2: test = test(3, 3)

The first are class variables, the second are instance variables. Let's focus on instance variables first.

certik avatar Jun 23 '24 19:06 certik

The TypeVar is causing conflicts in the symbol table as both the Struct and TypeVar have the same names.

tanay-man avatar Jun 24 '24 12:06 tanay-man

I think we should have just one "test" in the symbol table, which represents the class definition, it will be of type Struct.

And the corresponding StructType will be the type of the first argument self.

certik avatar Jun 24 '24 16:06 certik

I agree the problem is since TypeVar has the same name, we cannot add Struct (class definition) to the symbol table.

tanay-man avatar Jun 24 '24 18:06 tanay-man

What does LPython currently put into the symbol table for test = TypeVar("test")?

It seems it should just keep note of this variable internally in AST->ASR, but not expose it in ASR. The test variable will be only put into the symbol table once the class test is processed. The test = TypeVar("test") line is just a crutch that we use to make it work with CPython.

certik avatar Jun 24 '24 22:06 certik

What does LPython currently put into the symbol table for test = TypeVar("test")?

ASR before adding the Struct node :

(TranslationUnit
    (SymbolTable
        1
        {
            __main__:
                (Module
                    (SymbolTable
                        2
                        {
                            test:
                                (Variable
                                    2
                                    test
                                    []
                                    Local
                                    ()
                                    ()
                                    Default
                                    (TypeParameter
                                        test
                                    )
                                    ()
                                    Source
                                    Public
                                    Required
                                    .false.
                                )
                        })
                    __main__
                    []
                    .false.
                    .false.
                ),
            main_program:
                (Program
                    (SymbolTable
                        5
                        {
                            
                        })
                    main_program
                    []
                    []
                )
        })
    []
)

tanay-man avatar Jun 25 '24 07:06 tanay-man

I see, the test = TypeVar("test") is a Variable of type TypeParameter which is used for templates. Then in CPython this test gets shadowed. We could shadow it the same way. But why not use the simpler:

class test:
    def __init__(self: "test", x: i32, y: i32):
        self.x: i32 = x
        self.y: i32 = y

certik avatar Jun 25 '24 22:06 certik

self would of type: TypeParameter or Class or Struct??

Thirumalai-Shaktivel avatar Jun 26 '24 02:06 Thirumalai-Shaktivel

Can we treat self as a special argument? Whenever a function is declared inside a class, it can either have no arguments (if it's a static method) or at least one argument. We can assume the first argument to be a pointer to the object, and therefore, of the type of the class. Can we exempt the first argument from the type annotation requirement? We can treat self as this in lfortran.

tanay-man avatar Jun 26 '24 03:06 tanay-man

@tanay-man is suggesting the following example:

class test:
  def __init__(self, x: i32, y: i32):
    ...

Thirumalai-Shaktivel avatar Jun 26 '24 03:06 Thirumalai-Shaktivel