Skip to content

dataclass with Generic parameter does not honor default value #12962

New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Closed
aha79 opened this issue Jun 9, 2022 · 4 comments
Closed

dataclass with Generic parameter does not honor default value #12962

aha79 opened this issue Jun 9, 2022 · 4 comments

Comments

@aha79
Copy link

aha79 commented Jun 9, 2022

Bug Report

A dataclass with generic field does not infer the generics type when a default is provided.

To Reproduce

@dataclass
class Data(Generic[T]):
    field: T = 1
# -> "Incompatible types in assignment (expression has type "int", variable has type "T")"  (INCORRECT, should be accepted w/o error)

reveal_type( Data(17.5).field )
#  -> Revealed type is "builtins.float*"    (CORRECT)
reveal_type( Data().field )
#  -> Revealed type is "<nothing>"    (FAILED, should be int)

Expected Behavior

The default value supplied in the dataclass should be honored. Semantically the construct is not an assignment, but a default value
in the __init__ function:

Under the hood the (autogenerated) dataclass constructor looks like this

def __init__(self, field = 1):
     self.field = field 

So when field is not provided during construction of Data instance the field is passed as an int, so the generic type T should be inferred as int (if field is omitted in constructor). In the exactly same way as T is inferred as float when the field is given explicitly in the constructor (e.g. Data(17.5).field)

Concluding, what should happen:

  • Data() -> infer T as int (from the default in dataclass) (does not work)
  • Data(val) -> infer T as same type as val (this works)

Actual Behavior

Default argument is ignored

Your Environment

  • Mypy version used: 0.960
  • Mypy command-line flags:
  • Mypy configuration options from mypy.ini (and other config files):
  • Python version used: 3.9.7
  • Operating system and version: Windows 10
@aha79 aha79 added the bug mypy got something wrong label Jun 9, 2022
@aha79
Copy link
Author

aha79 commented Jun 9, 2022

#11923 seems to be a related issue

@erictraut
Copy link

I would not expect this to work. A dataclass decorator effectively adds a synthesized __init__ method to the class. For your sample, that method would look like the following:

def __init__(self, field: T = 1) -> None: ...

If you were to explicitly create a generic class with this __init__ method, mypy would similarly reject it because concrete default argument values are not supported for generic parameters.

@aha79
Copy link
Author

aha79 commented Jun 9, 2022

I see. So the real issue is that concrete default arguments are not allowed for generic parameters. However, after looking around on this site I found that this feature seems to meet some interest and has been requested several times so far (#4236, #3737, #10854, #10504, #5802, #5273, #5464, and perhaps more)

The issue is that the proposed workaround or solution with @overload (as in #4236 (comment)) does not work for dataclasses (or at least I cannot see how this would work in my case). With dataclasses the __init__ is autogenerated and manually overwriting __init__would undermine the purpose of using dataclasses in the first place.

The things is that when writing code with generics one arrives quickly at the point where the built-in default (T=Any) is not adequate.

@AlexWaygood
Copy link
Member

This isn't supported by the current type system, so I'm closing for now; but it sounds like you may be interested in python/peps#2717

# for free to join this conversation on GitHub. Already have an account? # to comment
Projects
None yet
Development

No branches or pull requests

3 participants