# PEP 718: subscriptable functions

**URL:** <https://discuss.python.org/t/pep-718-subscriptable-functions/28457>\
**Category:** PEPs\
**Tags:** typing, builtins\
**Created:** [June 24, 2023, 9:18pm UTC](https://discuss.python.org/t/pep-718-subscriptable-functions/28457 "2023-06-24T21:18:14Z")\
**Posts on this page:** 1\
**Showing post:** 38

<div class="post-metadata">

**Author:** ![Jelle](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/jelle/32/1049_2.png) [@Jelle](https://discuss.python.org/u/Jelle)\
**Post date:** [February 17, 2024, 4:05am UTC](https://discuss.python.org/t/pep-718-subscriptable-functions/28457/38 "2024-02-17T04:05:06Z")

</div>

I’m looking at the PEP again to see whether the use cases are strong enough to motivate a change to the core language. I feel that for this PEP to be accepted, it should give good examples of sound, type-safe code that is currently impossible or unduly verbose to write. Let’s go over the examples given in the PEP’s “Motivation” section.

## Empty containers

```python
def make_list[T](*args: T) -> list[T]: ...
reveal_type(make_list[int]()) # type is list[int]

```

This makes sense for the specific case of empty containers. Why would you write such a function, though? Are there examples of real users who needed this?

## Factory callable

```python
def factory[T](func: Callable[[T], Any]) -> Foo[T]: ...
reveal_type(factory[int](lambda x: "Hello World" * x)) # type is Foo[int]

```

This is a good example:

- I can imagine a type-safe implementation
- Type checkers would be able to tell if you use the wrong type. For example, if you wrote `factory[str]` on the second line, type checkers can flag that `"Hello World" * str` would fail.
- Type checkers can’t realistically infer this type, because other types could potentially exist that can be multiplied with a string.

On the other hand, there is a trivial workaround that works today: you can write `my_foo: Foo[int] = factory(lambda x: "Hello World" * x)`. Guido rightly points out above that this may be less convenient if the type is more complicated than just `Foo[int]`. Still, how common is this sort of thing in practice? Can you point to e.g. mypy issues where someone writing real code would have been helped by this?

## Undecidable inference

```python
def foo[T](x: Sequence[T] | T) -> list[T]: ...
reveal_type(foo[bytes](b"hello")) # list[bytes]

```

Here the function subscript helps the type checker decide whether to pick the `Sequence[T]` or the `T` branch of the union. But that is problematic, because it seems I could as well write `foo[int](b"hello")` and get `list[int]` back (since `bytes` is a `Sequence[int]`).

Yet at runtime, `foo` will only return either `list[int]` or `list[bytes]`, because its implementation can’t see whether we did `foo[int]` or `foo[bytes]`. Therefore, I don’t think there is a type-safe way to implement this `foo` function.

If we want to fix this undecidable inference, I feel we should do it instead by providing a more precise specification for type checkers on how to solve this type variable.

## Unsolvable type parameters

```python
def foo[T](x: list[T]) -> T: ...
reveal_type(foo[int]([])) # type is int

```

This is another function that is impossible to implement: how can it return an instance of an arbitrary type when given an empty list?

## Conclusion

This PEP needs a stronger motivation from real use cases. Two of the examples are useful, but I am not convinced that they represent common real-world code. Two others involve functions that cannot be implemented in a type-safe way.

I vaguely remember several cases over years of following typing discussions where subscripting functions has come up. However, the PEP does not link to any such cases, so I have to evaluate it based on the examples given in the PEP itself. Right now, those examples aren’t convincing enough for me to support the PEP.

(Speaking only for myself, not the Typing Council.)

---

_[View the full topic](https://discuss.python.org/t/pep-718-subscriptable-functions/28457)._
