I'm still amazed at how Python code with type hints looks so different to Python without them. Consider the program near the end of the article - if we remove the type hints:
- The `AstNode` abstract base class becomes completely unnecessary and can be deleted.
- We can't use `@dataclass` and are forced to write an `__init__` method for each class. But this is good, right? "Explicit is better than implicit"?
- It's then clear that our three classes each have two methods, one of which is __init__. Following the advice from "Stop Writing Classes" [0], each class should just be a function (in this case, a generator).
These changes reduce the code above "AST representation of the Ruby statement" from 70 lines to 40, and simplify some of those lines as well - for example, `arg_reprs = (arg.representations() for arg in self.args or [])` becomes simply `arg_reprs = args`.
The knock-on effects of type annotations seem to be doubling the complexity of the code. This is why I'm far from convinced that static type checking in Python is worth the cost.
If you're going to use Python with types, then you may as well use Nim. Nim has a similar syntax, but with better performance. You can also interface with Python code via Nimpy.
I love using Nim, it's an absolute pleasure after years of fighting with Python's "I hope I got this right..." style of type guessing. The biggest problem most people run into is that python has a huge library ecosystem.
I haven't actually tried interfacing them, it's next on my docket. Have you found any good learning resources for that?
A good test as an example: https://github.com/yglukhov/nimpy/blob/master/tests/tpyfromn...
I've tried it and it works fine. The only problem I ever had was trying to call a specific Python function at the same time from multiple Nim threads. I'm not sure where the fault lay exactly, I just made that part of the code single-threaded and moved on.