Skip to content

Intersections with Callable, in particular Any & Callable #16

Description

@randolf-scholz

In this issue, we shall discuss intersections with Callable. There is an unresolved issue with respect to Any & Callable, that stems from the following 2 axioms:

  1. Intersections with Callable are resolved by intersecting with an equivalent Callback-Protocol (see current draft)
  2. (x & y).foo = x.foo & y.foo (see Eric's outline: Handling of Any within an Intersection #1 (comment))

Both of these together can lead to infinite regress.

Therefore, we cannot use ① when intersecting function-types with function-types. One can distinguish 3 cases:

  1. Intersections of function-types with non-function-types: then we can apply rule ①
  2. Intersections of two function-types: regular subtyping and the more complicated function signature subtyping rules apply.
  3. Intersections of function-types with Any

EDIT: The suggestions below are outdated. The intersection with Any is irreducible. What needs to be discussed is what happens when the type is attempted to be evaluated with arguments args.


As I see it, there are 2 options of how to resolve ③:

For a strict interpretation of Any as an unknown type, Any could feasibly be Callable[..., R], which is a "consistent" subtype of Callable[[T1, T2, ..., Tn], R]. It follows that:

Any & Callable[[T1, T2, ..., Tn], R] = Callable[..., R]

The consequence is that (Any & T).foo(*args, **kwargs), is valid for any method foo of T, which as expressed in the Any intersection thread causes some pains, as it makes Any & T behave very similar to Any itself (only attribute types and function return types are preserved)

An alternative approach would hinge on a slight re-interpretation of Any in the context of intersections. One could demand that Any shall be interpreted as a disjoint type from whatever it is intersected with (= maximum compatibility). That is, in Any & T, we interpret Any as an unknown type that presumably shares no overlapping methods with T. This leads to

Any & Callable[[T1, T2, ..., Tn], R] = Callable[[T1, T2, ..., Tn], R]

I.e. we come back full circle to question if Any can be simplified away from intersections. Under this premise, we would have 3 simple rules, as I mentioned in #1 (comment)

  1. Any & T is an irreducible form
  2. (Any & T).fooT.foo if T implements foo
  3. (Any & T).barAny if T does not implement bar

So, does it make sense to have a general exemption to the rules #1 (comment) when intersecting Any with function-types?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions