One related PEP I think is useful to discuss/compare with as it can enable similar functionality as examples here.
def try_cast(form: TypeForm[T], value: object) -> Optional[T]: ...
trycast(Annotated[list[int], "..."], x)
vs
def try_cast[form: T](value: object) -> Optional[T]: ...
trycast[Annotated[list[int], "..."]](x)
What’s pros of doing typeform as a value to function vs as a type argument to a generic subscriptable function? Are there use cases of typeform that can not be written using latter approach?
Main tradeoff I see is this pep feels easier to implement at runtime and is straight forward to backport in typing extensions. PEP 718 requires a grammar change and runtime interpreter changes. To actually implement trycast some runtime dunder/builtin is also necessary to retrieve type argument. So runtime implementation wise TypeForm feels simpler.
On other hand PEP 718 looks simpler type system wise. Generic classes already exist and have mostly defined subscripting rules/behaviors. Re-using those subscripting rules for functions would make smaller type system change and I’d guess would be simpler type checker change.