Skip to content

Design of structs in LPython #2276

Open
@certik

Description

@certik

We want to map our structs into ordinary CPython. For now we use dataclasses, but #2275 shows that Python 3.11 changed a few things. So let's use this opportunity to design it in such a way that we just use the dataclass decorator directly from CPython, we do not wrap it in anyway.

Here are all the ways to use dataclasses that work in all Python versions including 3.11.

No Default Values

The first way is without initializing the members:

from dataclasses import dataclass
from numpy import array, ndarray

@dataclass
class X:
    a: int
    b: bool
    c: list[int]
    d: ndarray

def main0():
    x: X = X(123, True, [1, 2, 3], array([4, 5, 6]))
    print(x)
    assert x.a == 123
    assert x.b == True
    assert x.c[0] == 1
    assert x.d[1] == 5
    x.c[0] = 3
    x.d[0] = 3
    print(x)
    assert x.c[0] == 3
    assert x.d[0] == 3

main0()

The fields are mutable, and there is no problem at all, it works with lists and numpy arrays also.

Default Values

First of all, I don't think we need to provide default values. But if we do, here is how to do it:

from dataclasses import dataclass, field
from numpy import array, ndarray

@dataclass
class X:
    a: int = 123
    b: bool = True
    c: list[int] = field(default_factory=lambda: [1, 2, 3])
    d: ndarray = field(default_factory=lambda: array([4, 5, 6]))

def main0():
    x: X = X()
    print(x)
    assert x.a == 123
    assert x.b == True
    assert x.c[0] == 1
    assert x.d[1] == 5
    x.c[0] = 3
    x.d[0] = 3
    print(x)
    assert x.c[0] == 3
    assert x.d[0] == 3

main0()

This works for all Python versions including 3.11.

Arrays of Structs

This works in all Python versions.

from dataclasses import dataclass, field
from numpy import array, ndarray

@dataclass
class X:
    a: int = 123
    b: bool = True
    c: list[int] = field(default_factory=lambda: [1, 2, 3])
    d: ndarray = field(default_factory=lambda: array([4, 5, 6]))

def main0():
    x: ndarray = array([X(), X(), X()])
    print(x)
    x[0].a = 10
    x[0].c[1] = 10
    x[0].d[1] = 10

    x[2].a = 11
    x[2].c[1] = 11
    x[2].d[1] = 11
    print(x)

main0()

Using i32[3] Syntax

This seems to work for all Python versions.

from dataclasses import dataclass
from numpy import array, ndarray
from lpython import i32

@dataclass
class X:
    a: int
    b: bool
    c: list[int]
    d: i32[3]

def main0():
    x: X = X(123, True, [1, 2, 3], array([4, 5, 6]))
    print(x)
    assert x.a == 123
    assert x.b == True
    assert x.c[0] == 1
    assert x.d[1] == 5
    x.c[0] = 3
    x.d[0] = 3
    print(x)
    assert x.c[0] == 3
    assert x.d[0] == 3

main0()

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions