Closed dylon closed 1 year ago
One option is to treat Foo[:]
and Foo[1]
as syntactic sugar for Array[Foo, :]
and Array[Foo, 1]
. The "full form" Array
style can be implemented in CPython and can be used with custom user types like Foo
, while the syntactic sugar can still be used for builtin types like i32[:]
.
Something like this works for CPython, and the Array implementation for LPython could be modified similarly. TypeVarTuple is new in CPython 3.11.x, but it could easily be replaced with TypeVar as long as the respective parameter is a tuple.
from typing import Any, Dict, TypeVarTuple, TypeVar, Generic
from lpython import c32, c64, i8, i16, i32, i64, f32, f64, dataclass
import numpy as np
from numpy import empty
lp_to_np_types: Dict[Any, Any] = {
i8: np.int8,
i16: np.int16,
i32: np.int32,
i64: np.int64,
f32: np.float32,
f64: np.float64,
c32: np.complex64,
c64: np.complex128,
}
def lp_to_np_type(lp_type: Any) -> Any:
return lp_to_np_types.get(lp_type, lp_type)
DType = TypeVar('DType')
Shape = TypeVarTuple('Shape')
class Array(Generic[DType, *Shape]):
def __init__(self, dtype, *shape):
self.dtype = dtype # keep a reference to dtype since numpy will coerce any non-primitive type to "object"
self.shape = shape
self.data = empty(shape=shape, dtype=lp_to_np_type(dtype))
def __getitem__(self, idxs):
return self.data.__getitem__(idxs)
def __setitem__(self, idxs, vals):
self.data.__setitem__(idxs, vals)
@dataclass
class Foo:
x: i32
y: i32
def init(foos: Array[Foo, :]) -> None:
foos[0] = Foo(1, 2)
def main() -> None:
foos: Array[Foo, 1] = Array(Foo, 1)
init(foos)
print("foos[0].x =", foos[0].x)
main()
So the code in https://github.com/lcompilers/lpython/issues/1799#issuecomment-1546366342 should be made to work with LPython? I think making Foo[:]
work would be tricky, because dataclass
decorator in lpython.py
returns nothing but py_dataclass(arg)
i.e., CPython's dataclass object. Now, we might need to inherit this object in a new class and then override __getitem__
to return an Array
object. So instead of all these hacks, using Array[Foo, :]
would be better. @certik @dylon Let me know what do you folks think.
As @dylon wrote in https://github.com/lcompilers/lpython/issues/1799#issuecomment-1546366342, we should use Array[Foo, :]
, both in CPython and LPython. Let's make it work even for Array[i32, :]
, and then we will still support i32[:]
(as syntactic sugar).
I implemented the __class_getitem__
for dataclass
decorator in https://github.com/lcompilers/lpython/pull/1814, which seems to support the syntax in example shared in https://github.com/lcompilers/lpython/issues/1799#issue-1708014713. Since, it was a one-line change, I submitted it as a PR. Please kindly review it at your convenience, and if it doesn't meet the requirements, feel free to close the pull request.
I think this issue is now fixed. We support the Array[type, dims]
syntax. The example shared in the comment of this issue can be updated as follows:
(lp) ubaid@ubaids-MacBook-Pro lpython % git diff
diff --git a/examples/expr2.py b/examples/expr2.py
index afe5e8872..735c0c34f 100644
--- a/examples/expr2.py
+++ b/examples/expr2.py
@@ -1,5 +1,5 @@
# file: main.py
-from lpython import i32, dataclass
+from lpython import i32, dataclass, Array
from numpy import empty
@@ -8,11 +8,11 @@ class Foo:
x: i32
y: i32
-def init(foos: Foo[:]) -> None:
+def init(foos: Array[Foo, :]) -> None:
foos[0] = Foo(1, 2)
def main() -> None:
- foos: Foo[1] = empty(1, dtype=Foo)
+ foos: Array[Foo, 1] = empty(1, dtype=Foo)
init(foos)
print("foos[0].x =", foos[0].x)
(END)
Using the updated example, it works with both LPython and CPython.
from lpython import i32, dataclass, Array
from numpy import empty
@dataclass
class Foo:
x: i32
y: i32
def init(foos: Array[Foo, :]) -> None:
foos[0] = Foo(1, 2)
def main() -> None:
foos: Array[Foo, 1] = empty(1, dtype=Foo)
init(foos)
print("foos[0].x =", foos[0].x)
main()
$ python examples/expr2.py
foos[0].x = 1
$ lpython examples/expr2.py
foos[0].x = 1
Thanks @Shaikh-Ubaid for fixing this!
The following works perfectly well in LPython and LPython generates valid C code from it, but the syntax is not supported by CPython: