What if duck types are unions of all the ducklings
KotlinIsland opened this issue ยท 9 comments
If the duck typed types were actually unions of all the ducklings then it would fix a bunch of edge cases that arise.
And would make this feature more easily understood and discovered.
def func1(c: complex):
reveal_type(c) # float | int | complex
def func2(f: float):
reveal_type(f) # float | int
def func3(b: bytes):
reveal_type(b) # bytes | bytearray | memoryview
def func4(u: unicode): # python 2 moment
reveal_type(u) # unicode | str
edge cases:
def func(f: float):
f.is_integer() # error: int has no member "is_integer"
def func(f: float):
if not isinstance(f, float):
print("hi") # no 'unreachable code' error
reveal_type(f) # int | complex
It would also be useful to have type types for float
and bytes
, when you want exactly float
and don't want any stinking int
s.
This feature request appears to be based on a misunderstanding of the Python type system. The type annotation float
doesn't simply refer to the class float
. It represents a set of types that includes float
and all subtypes thereof. The type float
and the type float | int
refer to the same set of types, so they are equivalent.
This feature request appears to be based on a misunderstanding of the Python type system.
That's obviously not what I am saying lol. This issue is regarding addressing the problems introduced by the 'ducktyping' functionality defined in pep 484, which states that float
/int
should lie about their base classes (mypy extends this idea to bytes). The solution being that instead of lying about their bases (extremely confusing), these specific types should just expand to a union of the ducklings.
I don't understand what you're asking for here. I'm also not sure that you understood my previous point, so let me try again.
In type theory, if you have a class Parent
and a class Child
that derives from parent, then the types Parent
and Parent | Child
are 100% equivalent. If a type checker ever treats these as different, then it's a bug. If I understand you correctly, you're saying that float
should be "expanded to" float | int
, but those two types are 100% equivalent already because int
is (by definition in PEP 484) a subtype of float
. If mypy ever treats float
differently from float | int
, then it's a bug.
Are you suggesting that mypy add a new mode where it deviates from the behavior specified in PEP 484 and treats int
as though it's not a subtype of float
, etc.? That would be incompatible with all existing type stubs, so I don't think it would be very useful.
Or perhaps what you're asking is for new special forms to be added to the type system that represent "a float that is not an int" (float & ~int
), etc.? That would require a new specification in the form of a PEP, and the mypy issue tracker wouldn't be the right place to request such a change.
Or perhaps what you're saying is that when mypy prints the type builtins.float
in a textual form (e.g. in error messages), you always want it to print builtins.float | builtins.int
. That would be sound from a type perspective, but I think most mypy users would find that representation to be redundant, verbose, and even somewhat confusing.
Or perhaps I haven't yet captured what you're proposing. If that's the case, can you provide more specifics?
Edit: Now I get it. I totally missed the fact the hierarchy is fake for those very specific types. Been living too long on mypy-island.
I think @KotlinIsland wants
- the fake hierarchy undone, and
- for
float
, emitfloat | int
behind the scenes, and - some time later introduce
typing.FloatForReal
that won't have that union-emitting behavior
Probably subject for a typing issue...
@ikonst yeah, exactly. I plan on implementing this in basedmypy, it will be an interesting experiment.
@ikonst, what do you mean by "emit float | int
behind the scenes"? Will that result in any user-visible behavior change in mypy? If so, how? Is the only visible change that the textual output for reveal_type
and error messages becomes more verbose?
@ikonst, what do you mean by "emit
float | int
behind the scenes"? Will that result in any user-visible behavior change in mypy? If so, how? Is the only visible change that the textual output forreveal_type
and error messages becomes more verbose?
No, annotating something with float
will result in the type being float | int
. And the promotion/ducktyping will be removed from int
.
Ah, I see what you mean. Thanks for the explanation. Yeah, that's an interesting experiment. Let us know what you find.