Python is two languages now, and that's actually great

Everyone doing Python nowadays is aware Python supports optional type hints, and has for some time now. This has created a small schism in the community, with some people being completely uninterested in type hinting and a little defensive about the language partially going into a new direction, some people being very exciting about the potential of our evolving type tooling, and the vast majority of folks in the middle, not entirely sure where and how to apply type hinting best.

I am of the belief that currently, Python is actually two very similar programming languages sharing the same name. This certainly isn't a surprise to anyone who's been using Python for a while. What might be a surprise, though, is that I think this is actually a good thing. The languages, let's call them untyped Python and typed Python, even though sharing a very large common base are fundamentally different in how they enable the developers using them to solve problems.

Allow me to propose a model of thinking about code: there's infrastructure code and there's business logic code. Infrastructure code is exciting, powerful code that exposes easy-to-use interfaces that solve difficult and tricky problems, like talking to browsers (Flask), talking to databases (the Django ORM, SQLAlchemy), dependency injection frameworks (incant), serialization (cattrs) or defining classes (attrs, dataclasses). Business logic code is boring and unexciting code that enables you to solve problems and finish tickets and sprints at your day job. The point of infrastructure code is to enable and empower business logic code; business logic code provides the actual value to your employer, your users, or whomever is using what you're writing. Infrastructure code is the libraries you're using, business logic code is the code you yourself write and deploy.

(Note that this way of thinking about code is, like all abstractions, leaky. A library that you use may be a simple layer between other libraries and hence have all the characteristics of business logic code. If you're employed at a typical software developer position your work codebase will, almost certainly, have pieces of infrastructure code in it that you've written for that codebase. Even so, I find this way of thinking about software is very useful.)

It is usually impossible for infrastructure code to be fully type-hinted internally; the Python type system isn't, and probably never will be, powerful enough to support the types of operations libraries like cattrs and attrs need to do. This makes sense; one of the greatest strengths of untyped Python (and what brought me to Python in the first place) is that the infrastructure code available can offer amazingly friendly and powerful APIs. So untyped Python is, and has historically been, great for infrastructure code. Untyped Python is not very good for business logic code, which is why historically software developers have been quick to complain about maintaining large systems written in Python, and with good reason.

Business logic code is usually much simpler than infrastructure code, and there's a lot more of it in the world today; for each SQLAlchemy or Django, there are probably hundreds, if not millions of codebases actually using it in simple ways. Because of this, business logic code is an amazing match for typed Python. Using typed Python brings a ton of benefits to the development process, like moving entire categories of bugs from runtime into typechecking time, ease of refactoring (which is crucial for healthy codebase lifecycles), great editor suport (including autocomplete and robustly listing references, good code navigation) and lessening the need for tests (which increase the amount of code that needs to be written and maintained drastically).

For this marriage to work, we need infrastructure code not to be type-hinted internally, but to provide type-hinted interfaces at the code boundaries. This is exactly where the ecosystem is going, with noteworthy examples being SQLAlchemy 2.0 and a new generation of web frameworks like FastAPI. Also, as the Python type system matures it will enable a category of infrastructure code to be fully typed, but my gut feeling is that the most interesting pieces will still be untyped.

As for why is this a good thing: if you know one (typed or untyped Python), it's relatively easy for you to learn the other (an order of magnitude easier than learning a completely different language, in any case), and learning it will greatly empower you as a software developer.

Now, to address a potential elephant in the room: could we have had a single language good at both of these? I don't know, but I don't really think this was in the cards for a language like Python. I'm somewhat proficient in several different languages, so let's examine their situations:

  • JavaScript also seems to have a split situation with TypeScript, althought I don't know what the situation there is vis-a-vis infra vs business-logic code. Going to guess it's similar.
  • I haven't touched Java for almost a decade now, but I used to be very proficient at it. The Java I used was a business logic language through and through, which handily explains its popularity in the industry (since the vast majority of jobs in the industry are for writing business-logic code), the terrible interfaces all major libraries had, and the horror that was the ORM code I looked at once. I posit that Java is actually two languages as well, but that infrastructure Java is just very difficult to work with. This is why if a fellow developer tells me they've written an ORM in Python I'd excitedly want to share notes, but back then if a fellow developer had told me they'd written an ORM in Java, I'd look at them as if they were mad.
  • I think Rust has a very interesting approach to infrastructure code with their powerful macro system. I don't really know enough Rust to be able to comment with any confidence, but I suppose you can look at Rust macros as a different, infrastructure language on top of Rust. The way it feeds into (typed) Rust is especially elegant to me.

In conclusion: the addition of typed Python is a great thing for our community, and untyped Python isn't going anywhere. We just need to learn the right place for each, and work on combining them effectively.

Tin
Zagreb, Croatia