But to me, basically any cast() has a smell, and I wouldn't want to legitimize it by recommending that idiom.

I think I don't feel this as much as you do... a type guard is just a verbose conditional cast. Using cast has the advantage of not requiring runtime changes / requiring fairly minimal changes to type checkers, but if it's a concern maybe we could give it its own (hopefully less smelly) bikeshed, say assert_static_is_subtype.
 
If you don't want to define a two-line function, is that because you're writing short scripts? Or is it because you're worried about the runtime cost of the function call? (Then you should be worried about the cost of cast() also. :-)

My reluctance to define a function comes from a couple things:
  • For examples given in the PEP draft, like `len(val) == 2` or `all(isinstance(x, str) for x in val)`, I'd always write those inline today. Having to move around my code to define a two line but clunky looking function feels less ergonomic than adding a cast or an annotation. Especially if the function just gets used once or twice.
  • Runtime type checking has a lot of caveats. For my example of `not val or isinstance(val[0], str)`, picking a name like is_str_list_based_on_first_element to describe those caveats is clunkier than the actual code that does the check.
  • I sometimes write short scripts!
None of that is deal breaking, but since I didn't love TypeGuard, I thought it was worth bringing up cast as a lightweight construct that could be used to make code that is currently inexpressible in our type system expressible. In my mind, if cast supported redefinition like this today, the bar for the acceptance of a type guard like construct would be higher.

... discussion of safe cast ...

I bungled this minor suggestion — my terminology and links were a mess :-) I meant to refer to https://github.com/erictraut/peps/blob/master/pep-9999.rst#enforcing-strict-narrowing and some previous discussion on this thread. That is, should it be possible to further check that we only narrow to a subtype of the original type, e.g. `Tuple[int, ...]` to `Tuple[int, int]` as compared to `List[object]` to `List[str]` (or `int` to `str`). If this were desirable, it could be accomplished by use of a different cast function, perhaps called cast_narrower or downcast.

Hm. In my experience typeguard functions often naturally occur (though perhaps not for the examples given in the PEP) and they often abstract away checks that should not be inlined. So perhaps the use cases are just different?

Yeah, the use cases are definitely complementary / do not preclude one another. Like you say, I think there's an unmet need for `assert isinstance(x, TypeForm)` and cast redefinition could provide a solution for that.

That said, I'd like to know more about what use cases you envision for TypeGuard beyond code that currently tends to be inlined / maybe the PEP could benefit from a discussion of those. The TypedDict example in the current draft is well taken, though :-) (I'll note that you could still use cast redefinition in the appropriate scope, but it might feel annoying).


Shantanu

P.S.:

I feel the need to further clarify my confusing mention of an ill conceived safe_cast. This is basically irrelevant to the topic at hand, so please ignore.

The kind of casting that is typically safe is an "upcast" or "cast_broader". This corresponds to:
```
cast_broader(Union[int, str, bytes], 5)
```
This relates to type narrowing chiefly in that it makes it possible to avoid unwanted narrowing. This was relevant in the previous typing-sig discussion about whether a variable annotation should effectively perform an upcast. See https://github.com/python/mypy/issues/2008 and https://mail.python.org/archives/list/typing-sig@python.org/thread/GYVM5KEE6URE6PAH7UTK6324M7GWSFQS/

There's also "downcast" or "cast_narrower", which is pertinent here. This corresponds to:
```
x: Union[int, str, bytes]
cast_narrower(int, x) + 1
```
This obviously isn't safe. But it's less susceptible to obviously evil things if you check that int is a subtype of Union[int, str, bytes]. This corresponds to the discussion of "strict narrowing" in the draft TypeGuard PEP.