The new type system goes pretty much against the idea of duck typing, I'd consider that a pretty big fundamental change. And it's pretty half baked on top (e.g. `a: int = "foo"` goes through the python interpreter without even a warning).
And while there it certainly does provide a lot of benefits, it does make the language look more and more like a huge pile of patchwork and afterthoughts. It neither feels simple nor consistent and the tooling is a mess as well, both overly complex (e.g. half a dozens tools to do basic type checking) and lacking really basic important features (e.g. easy way to compile ship able binaries).
Especially after all the pain of the python3 transition, it feels just frustrating how much of a mess it all is. The "only one way to do it" philosophy seems to have been thrown overboard a long while ago.
> The new type system goes pretty much against the idea of duck typing
That's impossible, because it's not a type system at all.
It's type hinting, effectively a documentation feature, and sure, you can misdocument stuff. If people started building tools that rely on it to hack an actual type system on top of it, well, it's their problem. Duck typing is not affected by it in any way.
> And it's pretty half baked on top (e.g. `a: int = "foo"` goes through the python interpreter without even a warning).
Well, yeah, because that's a compile-time check, not a runtime check. Use Pydantic if you want runtime validations.
> The new type system goes pretty much against the idea of duck typing,
It's very much orthogonal, due to the aforementioned distinction. Type annotations are compile-time. Duck-typing is run-time. You can still type-hint something and then call an attribute that isn't on the interface, and you can suppress the type error with `# type: ignore`. But also, if you know you are using quack(), you probably want foo(duck: Duck).
> The new type system goes pretty much against the idea of duck typing
How so? Python’s Protocol and TypedDict have their limitations but are structurally typed.
> `a: int = "foo"` goes through the python interpreter without even a warning
As long as you’re validating inputs then you don’t need type validation at runtime. Input validation ensures that static types are representative of runtime types
Once you start adding Protocol and TypedDict you are (almost) back where C++ and Java are with virtual classes and interfaces. The point of duck typing was that you don't have to write all that boilerplate and stuff just works as long as the right functions are there. That's lost once you have to declare what you want to use.
> As long as you’re validating inputs then you don’t need type validation at runtime.
The issue is that type validation is done by a different tool, that follow similar, but not identical rules to the runtime. So it's very easy to create code that passes the type checker, but fails at runtime or vice versa. Type validation is something Python should be able to do itself, it's part of the language after all.
I'd heavily argue against "stuff just works". Without type annotations it's this wild west where stuff fails in prod because you don't have tests that cover every possible code path. With static type analysis, you're able get automatic test coverage for a huge swath of your codebase.
I can't count the number of times I've seen None-related errors in prod because some function deep in the business logic can't handle a None parameter.
Another huge benefit of type annotations is that it adds friction for clever code. As I've retroactively added type annotations to old code, I've discovered wild polymorphism. Some functions required upwards of 10 type signature overloads to account for all the polymorphism -- engineers have to remember all that polymorphism! Engineers won't write extremely polymorphic functions if they also have to write the convoluted overloads.
> The point of duck typing was that you don't have to write all that boilerplate and stuff just works as long as the right functions are there.
As long as your definition of "just works" is "run, crash, fix something, run, repeat". I remember the pre-type-annotation days, and still live it with some libraries. I find it quite unpleasant, but hey I guess some folks like the "freedom".
> So it's very easy to create code that passes the type checker, but fails at runtime or vice versa.
In theory, yes, in practice, not as much as you might think. If you actually use mypy with strict, which is actually really hard to do, you will find very, very few surprises.
This typing annotation system is just as half-baked as Python's class system. No, having syntax sugar for instancing "objects" that amount to new dictionaries is not an alternative to proper OOP.
And even having a "proper OOP system" means little when you have to dig knee deep in class hiararchy. Source: just had to debug a Java application today. Not my idea of fun.
Sometimes, planning stuff from the ground-up goes a long way to reducing future "code debt". Otherwise, leaving it at basics is sound enough.
And while there it certainly does provide a lot of benefits, it does make the language look more and more like a huge pile of patchwork and afterthoughts. It neither feels simple nor consistent and the tooling is a mess as well, both overly complex (e.g. half a dozens tools to do basic type checking) and lacking really basic important features (e.g. easy way to compile ship able binaries).
Especially after all the pain of the python3 transition, it feels just frustrating how much of a mess it all is. The "only one way to do it" philosophy seems to have been thrown overboard a long while ago.