On Tue, Dec 22, 2020 at 6:55 PM Shantanu Jain email@example.com wrote:
One concern I have is an inability to type narrow without creating a whole separate and fairly verbose function.
For instance, I'd often want to do an `is_str_list` check like this (rather than incur a linear cost):
if not val or isinstance(val, str): print(" ".join(val))
But to accomplish this I'd have to create another function and give it an awkward name like `is_str_list_based_on_first_element` so that it's clear that it's not safe in general.
I'm not convinced that this is much of an improvement over a possible alternative of mandating that type checkers support redefinitions with cast. The following reads really clearly to me:
if not val or isinstance(val, str): val = cast(List[str], val) print(" ".join(val))
It's too bad that we can't use ``` assert isinstance(val, List[str]) ``` for this situation, like we can in other cases (where the type is simpler).
But to me, basically any cast() has a smell, and I wouldn't want to legitimize it by recommending that idiom.
If you're like me and you inline most of the time you do this kind of narrowing, this is much less invasive to get things to type check.
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. :-)
If we got around to adding a safe_cast a la https://github.com/python/mypy/issues/5687, this would also allow the user to explicitly opt in to strict or non strict type narrowing.
(This confused me, thanks for posting the correct link: https://github.com/python/mypy/issues/5756 -- "Safe cast (upcast)".)
But even if we had a safe cast, in your example, presumably the base type is List[object], which isn't a superclass of List[str]. If it's List[Any] why would you bother with the cast? It would "typecheck" without it, and it would be just as safe at runtime (i.e., not very).
This would also easily allow narrowing of object members, as in Sebastian Kreft's QueryResult example.
Cast redefinitions feel really natural to me. I don't know what else one would want a cast redefinition to mean, so there seems little cost for type checkers to go ahead and support it, and we'd have a way to make the motivating use cases type check. Of course, we could then return to TypeGuard if we found it insufficient in practice.
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?