-
Notifications
You must be signed in to change notification settings - Fork 2
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
Add support for partial/full specialization of Generic interfaces #97
Conversation
... | ||
|
||
@interface.ImplementsInterface(AnInterface) | ||
class Specialization: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure this is 100% correct: the interface declares that every implementation should support any type as the parameter to foo
, like FooGeneric
does below.
Specialization
is specializing T
to str
, which violates the AnInterface
interface.
FooGeneric
works out of the box now, without the changes in _interface.py
in this PR.
I'm not sure the use case for Specialization
is totally valid.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It does work, but let's say I wrongfully implement Specialization
as:
@interface.ImplementsInterface(AnInterface)
class Specialization:
def foo(self, v: int) -> str:
return str(v) + "bar"
The above code works on runtime and on type_checking. However, it's clear that foo(self, v: int) -> str
differs from foo(self, v: T) -> T
but neither mypy or interface can see this Liskov substitution principle violation.
If we use Protocol
directly, we would have something like:
from typing import TypeVar, Protocol
T = TypeVar("T")
class AnInterface(Protocol[T]):
def foo(self, v: T) -> T:
...
class Specialization(AnInterface[str]):
def foo(self, v: int) -> str:
return str(v) + "bar"
spec = Specialization()
assert spec.foo(1) == "1bar"
what would cause:
src/oop_ext/interface/_tests/test_interface.py:1129: error: Argument 1 of "foo" is incompatible with supertype "AnInterface"; supertype defines the argument type as "str" [override]
src/oop_ext/interface/_tests/test_interface.py:1129: note: This violates the Liskov substitution principle
src/oop_ext/interface/_tests/test_interface.py:1129: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#incompatible-overrides
Seems like mypy is not properly checking the interface's structure
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
but neither mypy or interface can see this Liskov substitution principle violation.
mypy
does not know about our Interface
implementation at all, that's why -- it cannot konw that Specialization
and AnInterface
are related at all.
For new interface hierarchies, we should consider using plain ABC
classes and/or Protocols
, as they are natively interpreted by mypy.
(Btw in you example you are not supposed to subclass from AnInterface
).
3a9af7c
to
e885427
Compare
e885427
to
1335e8f
Compare
Kudos, SonarCloud Quality Gate passed! 0 Bugs No Coverage information |
As we discussed, in the end this does not seem to be the right approach. 👍 |
No description provided.