-
Notifications
You must be signed in to change notification settings - Fork 242
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
a way to refer to result type of an overloaded function #641
Comments
I can see how this can be useful, but this is pretty niche use case so I would say it is rather low priority. It would help to see other examples when this would be useful (e.g. some scenarios where precise type is impossible to express without this feature). |
Let me try to briefly describe my specific use case. I am implementing a module that allows building of Python wrappers around complex external data structures which are the typical combination of "objects" (in json sense), lists and dictionaries. Classes from this module are used in code generated from some external schema. The intended users of the generated code write Python-based configurations. Since those users are not necessary highly skilled Python developers, these wrappers attempt to provide exhaustive run-time type checking and also make best use of static type checking (e.g. with For brevity, I will omit dictionaries and will mention only objects and lists. import typing as tp
T = tp.TypeVar("T")
# note, this is not "x: tp.List[T]" but our own list defined below
@tp.overload
def typeSetter(x: "List[T]") -> tp.Union["List[T]", tp.Iterable["typeSetter.resultType(T)"]]:
...
@tp.overload
def typeSetter(x: T) -> T:
...
# just to silence the "An overloaded function outside a stub file must have an implementation" error
def typeSetter(x: tp.Any) -> tp.Any:
pass
class Object:
...
class ObjectField(tp.Generic[T]):
def __set_name__(self, owner: tp.Type[Object], name: str) -> None:
...
def __set__(self, instance: Object, value: typeSetter.resultType(T)) -> None:
...
def __get__(self, instance: Object, owner: tp.Type[Object]) -> T:
...
class List(tp.MutableSequence[T]):
...
# overloads for slice ommitted for brevity
def __getitem__(self, i: int) -> T:
...
def __setitem__(self, i: int, value: typeSetter.resultType(T)) -> None:
...
# of course, all the other methods required by MutableSequence
# some extra methods
def some_extra_method(self, x: int) -> None:
... The generated code could look like this: import typing as tp
import container_wrappers as cnt
T = tp.TypeVar("T")
class ExtList1(cnt.List[T]):
def some_extra_method2(self) -> None:
...
class ObjectType1(cnt.Object):
int_field = cnt.ObjectField[int]()
list_of_str_field = cnt.ObjectField[cnt.List[str]]()
list_of_list_of_str_field = cnt.ObjectField[cnt.List[ExtList1[str]]]()
class ObjectType2(cnt.Object):
obj1_list = cnt.ObjectField[ObjectType1]() The configuration code written by an inexperienced user whom I want to pamper with best diagnostics and code-completion experience possible: import generated_code
o1 = ObjectType1(...)
reveal_type(o1.int) # int
reveal_type(o1.list_of_str_field) # cnt.List[str]
o1.list_of_str.some_extra_method(1)
o1.list_of_str.some_extra_method("x") # error: first parameter must be "int"
o1.list_of_str = ["a", "b"]
o1.list_of_str = [1, 2] # error
o1.list_of_list_of_str_field = [["a", "b"], ["c"]]
t1 = o1.list_of_list_of_str_field[0]
reveal_type(t1) # ExtList1[str]
t1.some_extra_method2()
o1.list_of_list_of_str_field[1] = t1
o1.list_of_list_of_str_field = [[1], 1] # error
o2 = ObjectType2(...)
o2.obj1_list.append(o1)
o2.obj1_list.some_extra_method(1) As it is hopefully seen from the code, the key use for the functionality requested in this issue is ability to have different types for getters and setters. |
Please note that I have made the following correction: @tp.overload
-def typeSetter(x: "List[T]") -> tp.Union["List[T]", tp.Iterable[T]]:
+def typeSetter(x: "List[T]") -> tp.Union["List[T]", tp.Iterable["typeSetter.resultType(T)"]]:
... Actually, I have initially envisioned this feature as a generic pattern based type transformation (i.e. F[T1,...]->Tr) mechanism but it seems that piggybacking on existing function overload semantics and implementation makes it more likely to be accepted and easier to implement. |
Bump. I don't want to sound impatient but I would greatly appreciate any conclusions on the destiny of this feature, given my extra input, so as to be able to steer my future development. |
Sorry, this is not going to be implemented any time soon. If you want to be able to do effective type checking, I'm afraid you'll have to rethink your design a bit. |
I am looking for a way to refer to result type of an overloaded function.
To illustrate:
The
f.resultOf
syntax is, of course, tentative.Issue #623 seems to suggest that this may be achievable with a clever use of of
Protocol
but I just cannot twist my head around that.Upon request I can elaborate on my specific use case for this but I believe it would suffice to say that in real code
gf1.resultType
would be used multiple times. Specific argument types forgf1
were chosen arbitrarily for the sake of example.Not sure whether #548 is anyhow related.
The text was updated successfully, but these errors were encountered: