This Engineering Notebook post explains why type inference (and checking) is much easier than I ever imagined.
For over a decade, I believed that (while doing type inference) *everything depends on everything else*. I thought inferring the types (of objects) in module *A* required inferring the types in all other imported modules M1, M2, etc. That's just wildly wrong! Aha! It's dead easy to know the types of *names *imported from other modules!!! - "Import" statements *only* give access to top-level *names* from other modules. - Top-level declarations (in other modules) explicitly state the types of imported names. Let's take a closer look. The top-level statements of any module consist only of import statements, assignment statements, and definitions of classes and functions. Annotations give us the types of names in the LHS of the assignments. The types of classes and functions are the classes and functions themselves. The paragraph above contains some hand waving. Let's look at two difficulties: *The import graph* Imports statements create an implicit graph of *import dependencies*. mypy devotes considerable code to discovering strongly connected components <https://github.com/python/mypy/wiki/Build-Manager> (SCCs). These dependencies matter because changing module A might require reanalyzing modules that import A. Otoh, changing module A only *actually* matters if the change involves a top-level name in A. The dependency graph gives a *new view of Leo*. *By design, *the following are true: - leoGlobals.py imports no Leo modules, only Python library modules. - leoNodes.py imports only leoGlobals.py and signal_manager.py, which does not import any Leo imports. - leoCommands.py only imports leoNodes.py at the top level. *Commands.__init__* imports all of Leo's sub-commanders. These constraints (and others) ensure that Leo contains no circular import dependencies. In short, it's non-trivial to compute the dependency graph! A prototype might sidestep such complications--perhaps by using a hand-crafted dependency graph. *Function arguments* The only remaining difficulty involves inferring the types of function/method arguments. The Hindley-Milner so-called "algorithm" does this. This algorithm takes a *context* comprising the already-inferred arguments. I don't understand all the details. Happily, the details don't matter if (as in Leo) all arguments have annotations! *Summary* Type inference and checking remain tricky. But the details involve bookkeeping, not deep theory! The Hindley-Milner algorithm isn't needed if all arguments have annotations. These Ahas open the door to a super-fast *Leonine pylint*, as I'll explain in another ENB. This Leonine *pylint* should be about as fast as the existing Leonine *pyflakes*. Edward -- You received this message because you are subscribed to the Google Groups "leo-editor" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. To view this discussion on the web visit https://groups.google.com/d/msgid/leo-editor/f183bd4d-2257-4855-9556-1dd8b220fc3bn%40googlegroups.com.
