Proposal: Trait for strict, non-widening type bounds (solving LSP issues in binary ops)
#2143
kamalfarahani
started this conversation in
General
Replies: 1 comment
-
|
Since the new thing being expressed here is some additional constraints on typevar solving, I think it would be preferable if the new type system concept introduced were more narrowly targeted to typevar solving -- something more like https://discuss.python.org/t/support-function-with-multiple-generic-parameters-same-type/57931/6 Here it feels like we are introducing yet another variant of Protocols or ABCs (a type system feature with large surface area), just in order to (effectively) tweak the semantics of a generic protocol. |
Beta Was this translation helpful? Give feedback.
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Abstract
I propose introducing a new construct named
Trait. Unlike anABCorProtocol, aTraitacts as a strict constraint that prevents the type solver from "widening" aTypeVarto the base type. This specifically solves the long-standing issue of defining binary operations (like Semigroups) on subclasses without violating the Liskov Substitution Principle (LSP).The Problem: The "Binary Operation" Paradox
In current Python typing, if we want to define a generic binary operation, we often run into a conflict between type safety and LSP.
Why this fails today:
combineis called with anIntand aString, the type checker sees both satisfySemigroup. It resolvesTtoSemigroup.Semigroup.opmust accept any otherSemigroup. But for concrete logic (like addition), it must only accept its own type.The Solution:
TraitIf we define
Semigroupas aTrait, we change the rules of engagement. ATraitis not a "parent type" that objects can be widened to; it is a requirement that a concrete type must satisfy.Why this is better
Semigroupis aTraitand not a base class, we are not saying "Int is a Semigroup" in a way that requires substitution. We are saying "Int implements the Semigroup interface."TypeError: The type checker catches "mixed implementation" calls that currently pass when usingABCbounds.Proposed Semantics
Trait, and aTypeVarbound by aTraitcannot resolve to thatTrait.TypeVaris bound by aTrait, all arguments associated with thatTypeVarmust unify to the exact same concrete type.Beta Was this translation helpful? Give feedback.
All reactions