Type hints don't provide any safety, though. That was never the goal, given that they're strictly optional and don't really exist at runtime anyway (though I have written some experimental monstrosities that used annotations for code generation at runtime). They're documentation in a standard form that static analysis tools can leverage.
I really can't imagine a situation where having type hints in Python is worse than simply not having them. They're not the worst of both worlds, they're a compromise with some of the benefits and drawbacks of each.
Can’t they lie / go out of sync with what’s actually happening? IMO, an unenforced type hint is very dangerous because of this - it can give you a false sense of confidence in a scenario where you would otherwise write more defensive code.
Defensive code is good, but I'm absolutely sick of writing code that has to be defensive about the type of absolutely every variable everywhere. It's ridiculous, verbose, and nearly impossible to do universally. THAT is the worst of both worlds. Having to manually fret about the types that every variable may hold. At the point that you're having to write defensive code due to dynamic types, you've already lost the advantages of dynamic types entirely.
I use type hints to say "use and expect these types or get Undefined Behavior", and that contract is good enough for me.
This is demonstrably untrue with the default configuration of Mypy. It will silently ignore explicit hints, inline or not, in certain situations.
If it's demonstrably untrue, you should be able to demonstrate it, right?
https://paste.sr.ht/~chiefnoah/7e07a961cf266fa620d1fd2d31ba2...
This particular issue will get picked up with `--strict`, but it's nearly impossible to do that on a large codebase with typing added post-hoc.
Pyright has saner defaults, it catches this particular issue: https://paste.sr.ht/~chiefnoah/80816fded2a08a03ca80804d524ee...
I agree, though. Pyright has better defaults. It's not great that mypy just completely skips all functions without typing information given. It makes a lot more sense for it to just check everything and assume Any on all unspecified arguments and returns. It's still valuable to type-check the contents of functions with unspecified types.
I used to think this, but based on experience I'm now less convinced. Finding most bugs, like real static typing does, is great; you can significantly reduce your test coverage and iterate with more confidence. Finding a few bugs is pretty useless if you're not finding enough to actually change your workflow.
It's not about workflow or finding enough bugs, but finding bugs that you might not have otherwise seen can be monumentally beneficial.
There's a kind of excluded middle here though. Either that kind of bug hits production often enough to matter - in which case a checker that catches it sometimes isn't good enough, you need a checker that eliminates it completely. Or it doesn't hit production often enough to matter, in which case a checker is of limited use.
Writing type annotations in comments for an optional preprocessor to pass judgement on before the actual implementation ignores them is a bad thing. But that's on python, not on gradual typing.
(An any type + static is also fine if you have a way to retrieve type information at runtime, and there's a sense in which template instantiations of a generic function and a function taking arguments of type any are the same thing as each other)