Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
Pyre: A performant type-checker for Python 3 (pyre-check.org)
140 points by tosh on May 10, 2021 | hide | past | favorite | 115 comments


Big discussion with over 500 comments from 3 years ago: https://news.ycombinator.com/item?id=17048446


So three years passed and static checkers have gotten even more traction. What's the best option for Python so far for small projects today?

I tried mypy [1] before but it was a bit cumbersome to keep it checking my code. At work I use pytype [2]. It's good enough but that's only because someone else made a build system integration for me. Pyre's scan-all-the-files approach seems easier to get started. Is there any catch? Which one are you using and what's your impression?

  [1] https://mypy.readthedocs.io/en/stable/
  [2] https://github.com/google/pytype


I've used mypy and pyright. Mypy generally "just works" for all the Python idioms I use, while pyright is less reliable.

Pyright's VSCode integration, Pylance, provides a great auto complete experience. So I use Pyright for autocomplete in VSCode and mypy for type checking.


Last I checked, mypy struggled to represent recursive types. Think `JSON = Union[None, bool, str, float, int, List['JSON'], Dict[str, 'JSON']`. That's a bummer because recursive data types are darn handy.

Worse, importing third party packages often fails silently and when you can get error messages they tend to be completely inactionable (I recall one error message which linked to a web page that had lots of details and workarounds for fixing other problems, but none of which solved the error itself).

Figuring out how to distribute my own type annotations was similarly painful. IIRC, you have to drop a specially-named file into a particular directory and this is all undocumented save for a dense PEP and the error messages are unsurprisingly terrible. All of these things are actionable, but the progress seems slow (these have been among my top grievances since the project debuted, so the maintainers and I have different priorities, clearly).

The problems for which I'm less optimistic tend to revolve around shoehorning typing into existing Python syntax--e.g., to get a callback that takes kwargs you have to define a protocol with a `__call__` method that takes kwargs because you can't express it with `typing.Callable`. Similarly where a language with first-class support for types might have `type Foo<T>`, Python makes you write `T = TypeVar("T"); class Foo(Generic[T])` or something like that, and it gets more confusing when you only want one of the methods to be generic and I can never remember whether that `T` takes on a single type across all uses or which scope I need to define it in, etc. This is largely an ergonomic nightmare and I don't have lots of optimism for this stuff to improve unless the Python community really comes to embrace typing as the default way to use Python (but I suspect most people who care a lot about this kind of stuff will leave for Go or other languages where these things just work out of the box).


I have yet to successfully build a project with the strict mypy settings, without resorting to either turning some off or having to use an explicit Any. And a lot of the non-default settings are absolutely critical if you care about correctness.

Lack of recursive types has been a major deal breaker for me. If you have a class Foo that can construct a class Bar, and a class Bar that can construct a class Foo, you can't express that in mypy without Any-Generics.

To me, at this point, mypy is barely a linter, it's more of a "this helps my IDE autocomplete faster", and definitely not a type system.


I also struggle with Mypy's strict mode, but I think recursive types are different from classes that can construct each other. Mypy doesn't have any problem with the following code

    from __future__ import annotations


    class X:
        def __init__(self, value: int) -> None:
            self.value = value

        def to_y(self) -> Y:
            return Y(self.value)


    class Y:
        def __init__(self, value: int) -> None:
            self.value = value

        def to_x(self) -> X:
            return X(self.value)


    x = X(10).to_y().to_x()
    print(x.value)


Sorry, yes, that works. I should have been a little more explicit. This breaks down when Y is generic over X and X is generic over Y. IDK, I've had tons of problems with mutually recursive TypeVars, though my example was not of that - sorry.


This pretty much mirrors my mypy experience too. The only project I've ever successfully used it on was a single-file CLI tool that only used the stdlib.

And by "successfully" I mean "it ran at all". Every other thing I've thrown at it has caused it to crash. I quite like the concept, but implementation has been rather abysmal as far as I've seen. Has it improved in ~ the past year?


I've been using it recently, but just as a vscode plug in for type hints, I don't run any additional checks afterwards, but it seems to catch type errors before execution. But it's been cpu intensive in a wsl container on larger >2k line py files. I haven't tried many others tho, so not really sure if there are better options out there.


Not really, no.


> Similarly where a language with first-class support for types might have `type Foo<T>`, Python makes you write `T = TypeVar("T"); class Foo(Generic[T])` or something like that, and it gets more confusing when you only want one of the methods to be generic and I can never remember whether that `T` takes on a single type across all uses or which scope I need to define it in, etc.

I don't know about you but I find PEP 484 very clear here: https://www.python.org/dev/peps/pep-0484/#scoping-rules-for-...


The PEP is clear, it's just extremely unintuitive that, within the scope of declaration, a type T can be many different types.


Fair enough. Maybe I didn't come across that at the time or perhaps it's been since revised. Even still, it's a poor substitution for the more familiar / intuitive `class Foo[T]:` / `def foo[T](...)` style.


Hmm it might take some getting used to but I've actually found it quite straight-forward to comprehend and reason about.

The nice thing is that, since TypeVars are ordinary variables, you can re-use them / import them in multiple modules and avoid a lot of boilerplate code.


> The nice thing is that, since TypeVars are ordinary variables, you can re-use them / import them in multiple modules and avoid a lot of boilerplate code.

Maybe I'm missing something, but the boilerplate only exists because Python makes you define them as ordinary variables in the first place. So while you can have a `foo.py` file like this:

    T = TypeVar("T")
And a `bar.py` file like this:

    from foo import T

    class Bar(Generic[T]):
        ...
So are you saying that this is less boilerplate than a `bar.py` that just defines its own `T` TypeVar? Because that seems like a pretty comparable amount of boilerplate. Or are you saying that it's less boilerplate than languages that don't treat TypeVars as ordinary variables, e.g., Rust? Because in Rust our `bar.rs` file would look like this: `struct Bar<T> {...}` (and the scoping rules are patently obvious, to boot).


No, in this particular example, there's no real advantage. What I meant were situations where the TypeVar gets a little more complicated, compare the additional parameters on https://docs.python.org/3/library/typing.html#typing.TypeVar . Then importing TypeVars starts to pay off because you only have to define your bounds etc. once.


Ah, that makes sense. Thanks for clarifying.


This is all true. So true infact that I wrote a huge article documenting this for people who are new to it: https://tshr.me/mypy

I'm planning to migrate this to my own blog soon.


> The problems for which I'm less optimistic tend to revolve around shoehorning typing into existing Python syntax--e.g., to get a callback that takes kwargs you have to define a protocol with a `__call__` method that takes kwargs because you can't express it with `typing.Callable`

You might be interested in the discussion over here then -> https://github.com/python/typing/issues/769#issuecomment-741...


Seconding this setup for both VSCode and emacs


As someone who hasn't started using types in Python seriously yet, it's a bit discouraging to see that there are already so many competing type checkers with different approaches and no clear winner. I understand that the problem is a bit harder than `{go, cargo} fmt`, but I feel we'd be better off with one type checker to rule them all.

Or does it mean that we should check types using all type-checkers available to have the most compliant code possible?


In practice they are quite similar in errors reported. There are differences that pop up but most of the time either it is bug to report or one has implemented a certain pep faster than another. A few rare things are extra type checking support entirely like pyright supports recursive types but mypy does not (or pyre has best tensor related support but those are future peps). Mypy's biggest unique thing is plugin support and some very dynamic libraries use plugins for better coverage. The differences should become peps if important enough and then eventually be supported by all 4.

I think for most people any of the 4 big ones is fine. Most of the common type errors will look identical regardless of which you pick. Configuring multiple in CI is pretty straightforward if you want to go full. My current codebase has mypy + pyright configured. Pyright was a mix of fast response time on github issues + I use vscode and was the one that added type checks to CI.

If you want a deep dive pycon is this week I think and there's a day for type checking related talks including one talk comparing the 4. I think type checking day is thursday.


Thanks for the tip! Posting link here for the reference: https://us.pycon.org/2021/summits/typing/

Hope they post the recordings somewhere later.


No, multiple checkers will drive you crazy because one type checker will support one feature while another will report errors for it.


Whichever option you take, stick it into pre-commit. A good pre-commit-config.yaml is quality-of-life changing.


have you had any problems using the open source version of pytype? we've tried to make it easy to just drop in to your setup.cfg and automatically analyse an entire project; if there are things that don't work we'd love bug reports for them!


No. I didn't expect it to be non-blaze/bazel tool friendly, but sounds like it is (aims to be at lest)?

It does seems to support the entire-directory parsing as well. That's nice! Let me give it a try next time. Thanks for the tip!

As a reminder to myself, here is the link to the doc: https://google.github.io/pytype/


I'd advise to give mypy yet another try but disable in config file error codes that are painful and # noqa or # type: ignore lines that can't be understood well by mypy.


I'm not sure what you mean by "cannot be understood well". Either the type annotation is correct or not. If there is a genuine bug in mypy, the recommended convention is to use "type: ignore" (ideally with a reference to a bug tracking id). If you are genuinely subverting the typesystem, then use a cast(). If the code is too complex to type correctly or the type cannot be expressed in the typesystem (e.g. recursive types) then use type Any.


I personally use neovim with coc-pyright plugin. It integrates remarkably well mypy. It has saved me so many hours of development, I just can't dev without it nowadays.


Mypy and Pyre appear to be the only two that work really well and can solve type-checking issues at scale.


PyCharm works well for me. Probably not as fancy as all this other stuff, but the type hints make the code easier to understand, and they help PyCharm help me by enabling it to find more errors and by enabling enhanced autocompletion.


PyCharm having type checking built in is excellent, but it is definitely the lowest quality out of the major 3 (Mypy, Pyright, Pyre) with respect to correctness.


I've always found its type checking to be perfectly fine, but hearing its not the best I might look into the others.


It tends to be overly-lenient about certain return types and tends to miss some more advanced type inferences.

It's a great tool when editing code. But you still should run Mypy or another checker for more-correct analysis.


What type checker does PyCharm use? In-house?


Yes, in house


As with package managers, there seem to be half a dozen different, competing type checkers for Python now...


Yeah and even worse they disagree about type errors!

We really need a modern Python alternative. I don't know of any that don't give up the REPL / single file script features which are pretty huge advantages of Python to be honest.


Wouldn't Julia be that language? Its fast, supports static typing, and is built from the ground up for machine learning/ data science. It also has a built in REPL.


Julia is that language now. Previously I had sunk cost fallacy regarding Python, but now we are building a brand new application from scratch, and we chose Julia.


Julia is nothing like Python though, and it has other flaws like 1-based indexing and huge delays loading packages as it compiles them.


How is it nothing like Python?

1-based indexing is definitely not a flaw. And version 1.6 massively decreased package import and precompilation time.


> 1-based indexing is definitely not a flaw.

It really is. We've known it for literally decades:

https://www.cs.utexas.edu/users/EWD/transcriptions/EWD08xx/E...


It really depends on what you do - sometimes offsets are better, sometimes an index is better. If you really want 0-based indexing, you can have it! https://github.com/JuliaArrays/OffsetArrays.jl

My own preference is random indexing, it's so much more exciting to be surprised https://www.juliabloggers.com/random-based-indexing-for-arra...


It's radically different, but the language where I've had the most pleasant repl-driven experience is Elixir. Because of how it's error handling works it's even sane to debug with a repl into live production in some cases.


I've started learning Elixir over the week and I can't see myself using Python for scripting again. They're very different languages but th experience feels similar, except I vastly prefer Elixir


I wouldn't expect elixir to be good at scripting. What sort of libraries do you use?


GNU Guile can do that easily, as probably many other languages. The ecosystem is what makes people stick to Python, especially in areas like data science. Ecosystems are generally difficult to compete with, because they rely a lot on mind share. Mind share is a bit like gravity, in that clumps of matter will collect more matter. It takes very motivated people to implement solutions anew in another language, piece by piece getting an ecosystem up to speed. Or a lot of money.


GNU Guile is a weird Lisp variant. Nobody is switching from Python to that; be realistic.

I do agree in some applications like data science / machine learning you could never get people to switch from Python because everyone uses it. But Python is also used for loads of other things, e.g. hacky build systems, web scraping, etc. that could easily switch.


It is actually more precisely a Scheme dialect. I used Racket for some time and then moved to Guile. I do not find it weird, having used other lispy languages before.

Guile has many useful tools, like OS level threads and also a fibers library, community projects, a good manual, albeit sometimes lacking a few examples, an active community and mailing list and more. Since it is a Scheme, it adheres to a Scheme standard, which specifies many things already. Then it implements many SRFIs, which also specify many things. I guess, that you name something that goes beyond the Scheme standard and beyond the SRFIs "weird".

Could you point out what more specifically you personally find weird about it?


Lisp has been around for 60 years. Its adoption is lower than Cobol's or Fortran's and definitely lower than that of modern languages. Despite multiple commercial pushes over the decades.

That's what's weird.


Wait, now we are switchting targets? What is this talk about Lisp? What Lisp? Or are you referring to the LISP? And what does it have to do with GNU Guile being perceived as weird by someone else? Right now it looks like you are talking about something unrelated.

Usually when someone claims, that something is "weird", I want to know, why they think so. When it is about programming languages, I would like to know what it is exactly, that they think is weird about that specific language and that is what my question entailed.


Guile suffers from the same problems any Lisp does: parantheses everywhere, the code all looks the same. Lisp devs love it (Yay! Homoiconicity! Code is data and data is code!), average devs hate it, it's hard for them to figure at a glance what's what.

Then, macros and DSLs are awesome for solo cowboy coders writing code, not so great for professional programmers working in large teams and reading code 10-100 times more than they write code. This also leads to fragmentation and half finished solutions since the solo devs generally scratch the itch but don't do the hard work required by the last 20% of the project (which as we know, takes 80% of the time).

Then, adoption. It's not there. There are no IDEs except for Emacs (not a popular editor/IDE) or commercial ones which are super expensive. Libraries are in much lower quantity and variety and frequently not as good as those of mainstream languages. Etc, etc.


The average dev has never taken a look at a lispy language and so cannot hate it. For the ones being hesitant to dip their toes in it, how can they really hate, what they do not know? It seems more like not being interest, than "hating" it, where "it" is the essence of such a language.

Macros, DSLs, well, of course you can abuse then, like anything else in computer programming. However, there are many examples of how they can be used in a great way. Look at some Racket macro things like typed Racket for example. Or look at pipelining operators. Or timing. Or memoization. All these are very well usable and there is no problem with using them in a team. Well written macros allow taking cool features from other languages to your Scheme dialect of choice.

Emacs is still well liked. I recommend you get on the mailing list and read a few weeks about how varied its usage is. Very active mailing list.

Libraries of lower quality? Even "much lower"? Where is your source for that? Not sure which specific ecosystem you have looked at, but that experience is completely different from mine.

Aside from the fact, that I can usually solve the problems by just using Guile features, Scheme and SRFIs, not even needing an external library, there are very clever people active in the ecosystems of lispy languages (including GNU Guile) and FP languages, outputting high quality code, often going beyond what some mainstream language library does, while using good abstractions to do so.

It is important, that languages like GNU Guile, which implement interesting and powerful concepts, continue to attract people, who want to learn more than the mainstream fad and improve the status quo. It is a great journey of learning, which I recommend to any software developer looking to widen their horizon and to improve their skill.


Guile suffers from being a great language then?


All ML derived languages, Lisp based languages have REPL, you can put everything on one file if you feel like it, and they compile to native code.

Then there is Julia as well.


Node.js has a REPL, and there's nothing stopping you from putting your entire project into a single file.


True, but to use JavaScript sensibly you really need to use Typescript and ESLint (to ban the crazy old features like `var` and `==`).

But I do agree Typescript is one of the best alternatives today if you can stomach `tsconfig.json` `eslintrc` and `node_modules`.


nim is the closest I've found. Really hoping it gains more traction.


... is there some problem with having multiple choices of libraries?


I think it'd be nice if they settled on a standard as to what is a correctly typed program.

Mypy and Pyre are pretty similar, but Pytype has very different standards.


If type analysis tools show different issues, fixing one should not break the other, unless the other is wrong? They both are trying to model the same language/runtime.


It's starting to look like the huge embarrassment that is python packaging and environment management. I work with the language every day, and I still have no idea what am I supposed to use between conda, pip, setuptools/setup.py, pyproject, meta.yml, poetry, pipenv, etc...

Conda is so slow that I sometimes wonder if we are being trolled by some cruel God of programming. Pip is faster, but version resolution is iffy.

Hell, even just assigning versions to python packages is nothing short of ridiculous. Do you use version.txt in the root folder and set it manually? Do you have it set from SCM? Which of the half a dozen packages do you use to have it set from SCM? setuptools_scm? Versioneer?

There are a set of tools in the python ecosystem that have basically no equal in any other language and these tools and the surrounding mindshare make python irreplaceable in the near term. The language itself is easy to learn and powerful enough to be able to do data analysis with ease. Good python code is easy on the eyes, which I personally consider an important aspect.

Outside of these tools, core parts of the ecosystem are basically an XKCD joke.

I tried switching to Julia as I find both the language and the ecosystem are vastly superior in their foundations. Unfortunately the maturity is not there yet, and neither is the mindshare. If I had to bet my career on adopting the language in a business setting, I'd not be prepared to do so. Which is a shame, because the situation turns into a Catch-22.


I feel like the problem is that pip is clearly the most popular, but philosophically the pip developers do not want to build a solution to all packaging and environment management into pip.

If I were pip dictator, I would try to make pip the one tool to handle all python packaging and environment management. In particular, that means pip would handle the management of different Python versions, different Python environments, native dependencies, running tests, making builds perfectly reproducible, releasing new versions of libraries, and creating new projects.

"Creating new projects" seems like it is not a big deal, but in practice I think that if there were simply a "pip new" command that set up a new project using the best practices advocated by the pip team, it would go a long way toward standardizing the ecosystem here.


You're kind of describing poetry. I think Python has a real future with solved packaging if Poetry can get the backing it needs at the language level.


Try mamba instead of conda [0]. It's really fast.

The first time you have to run it as:

    conda install -c conda-forge mamba
From then on, you replace conda with mamba. For example, if you are installing dask-cuda from the rapidsai channel you run it as:

    mamba install -c rapidsai dask-cuda
At this point, mamba is just so much better and faster, that it's the first package I install in an Anaconda environment.

[0] https://github.com/mamba-org/mamba


Unfortunately mamba doesn't support working behind proxies (so it's a non-starter in most corporate environments) and it's anecdotal but I've had it fail and crash much more so than conda does. It is faster indeed, but there's the other aspect as another poster points out: there's now Mamba and Conda, so instead of having one standard, we now have two. Plus, mamba can't be used for creating and managing environments, so you still have to do 'coda env create ...' for example.


That's exactly the problem: instead of using conda you should instead use one of the myriad of others! It's balkanisation.


Starting to? The Python ecosystem has been pretty behind other languages for more like 10 years now. I'm still forced to use it for work but it's becoming more and more likely that "no python" will be a hard requirement for my next job search...

What tools do you find irreplaceable?


There are actually clear answers to all your questions.

All the tools you listed do different things, except maybe poetry and pipenv, so you can pick whichever one you like, you're not supposed to do anything. You can have choice, illusion of free will, etc...

As to module version, there is a standard on how to define it in __version__: https://www.python.org/dev/peps/pep-0008/#module-level-dunde...


> There are actually clear answers to all your questions.

Strongly disagree. Conda, pipenv, pyenv, venv, poetry are all trying to solve the same problem (although conda tries to solve some other problems too).

Choice is not always good, this is why we have standards.

I would recommend pyenv. I understand why people are attracted to poetry, but pyenv arguably offers all of the same benefits that poetry has as well, and has better adoption.


> Strongly disagree. Conda, pipenv, pyenv, venv, poetry are all trying to solve the same problem (although conda tries to solve some other problems too).

Not really, some of these manage the issue of multiple system pythons (pyenv), while some manage isolated envs for particular projects (venv), and some try to be wholistic python project and dependency managers (pipenv, poetry, arguably venv + pip freeze, but that's not "wholistic"). Conda sort of tries to be all of the above as well as a bunch of other things (high performance options etc.)


Pyenv also has isolated envs for specific projects, poetry also tries to solve that problem.

There is a ton of overlap, denying that is disingenuous.


While there is overlap, there's also a ton of differences (pyproject for dependencies, dependency resolution, version locks).

I use both pyenv and poetry, and basically nothing else apart from the occasional call to pip.

I cannot imagine dropping poetry and only use pyenv, but I can imagine dropping pyenv (have been looking at asdf recently...)


Just use setup.py and __version__, ignore fashion until a winner emerges. Hasn’t failed me in ~twenty years.


This doesn't allow you to create conda packages, so you have to install things via pip. This can then cause headaches as you now have two mechanisms by which package versions are managed. Or you give up conda entirely and the scientific python ecosystem that comes with it.


Yes, most libraries have wheels, many others can be compiled, or installed from packages online.


Python type checking has entered a serious xkcd 927 phase that will get worse before it gets better.


I'd posit you are being optimistic there. Just look at the python packaging story. It had 20 years to get better and it's still only getting worse.


We unfortunately had to switch away from this as it took too long for pyre to support Python 3.8 after it was released. I've been using mypy since then, but I had no complaints about pyre when I used it.


Is it just me or does type checking python break the idea of python? If you wanted type checking shouldn't you just use a different language that has a sensible type model to begin with?


A Tale of two types systems -> now: a Tale of three types systems? To make it a book title, The three type systems problem?


How are three type systems? The type annotations are part of the Python 3. You can use multiple libraries to analyze the types. There are also multiple static type analysis tools for C, and for other languages that have type definitions as part of the language. How is this an issue, what am I missing something?


When you write types in Python, the interpretation of your type annotations are up to the type checker. Your annotations that you write for e.g. Pyre may not type check in mypy. The end result is that your type annotations are not "Python" type annotations, but "Pyre"/"mypy"/etc. type annotations.

In C, you ultimately care about what the compiler says. And this has also led to dialect-specific C code that works fine in one compiler but doesn't compile or runs incorrectly in another compiler.


Not that much as they all follow pep 484 + a few other peps. The number of type features unique to each one are generally bugs/recent peps they haven't implemented. The biggest one is mypy plugin ecosystem although the hope there is to either do more peps that plugins become no longer needed and the type system is strong enough to cover more things or make a plugin pep.

If you are using the most recent pep features possible than yeah you might have an issue. That's similar to clang/gcc both taking time to implement new c++ standards and not being compatible there. If you only use pep 484 which covers most basics well then you should be good for any checker.


> Not that much as they all follow pep 484 + a few other peps. The number of type features unique to each one are generally bugs/recent peps they haven't implemented.

This is totally untrue? Pyre adds completely new notions like taint analysis, pytype adds a totally different inference system - the type systems are not compatible and it has nothing to do with implementation of PEPs.

The difference with C is that all of the other linters and analyzers are on top of the base type system, they don't replace it. In the case of Python the only standard part is where the annotations go and how they get resolved at runtime, it's otherwise completely up to the type system implementation to determine what's what, and all 3 of them do so in very different ways.

This is like if clang/gcc had totally different behaviors for `auto` in C++, but really it's not even comparable.


The inference system and the type system are separate. Pyright uses a very different inference algorithm than mypy for better incremental support. It remains pep 484 compliant like mypy. Pyre's taint analysis is separate from pep 484 and is something different from type checking. Pyre explicitly describes taint analysis as separate from base type checking, "Pyre has applications beyond type checking python code: it can also run static analysis, more specifically called Taint Analysis, to identify potential security issues. "

My base statement of 4 main type checkers are pep 484 compliant and that's main type checking most people refer to for python. If you get a type error that's inconsistent with that pep that's a bug. If you use a feature outside of any pep like plugins, taint analysis, pyright stub generation, then yes that is unspecified and can vary. Most engineers I work with python type checking stops mostly at basic type system and I'll sometimes point them to newer peps for better type definitions. My actual experience is most places don't consistently do any type checking at all although people tend to be open to it if you're fine guiding them/setting it up.


    $ python -c 'import this' | sed -n 15p
    There should be one-- and preferably only one --obvious way to do it.
Sadly, the python type-checking situation appears to be going the way of the python packaging situation.


Been using coc-pyright with coc.nvim and I am a fan.

Issues seem to be from libraries with crappy, incomplete, or incorrect typing/stubs, not from the checker itself.

Every day I tire more and more of using Python for larger projects for these reasons


Unrelated funny little fact for lovers of scifi novels: Pyre (PyrE) was the name of an extremely rare element and main plot device for the novel Tiger! Tiger! (aka. "The Stars My Destination"), by Alfred Bester:

https://www.amazon.com/dp/B01MRJVUPC/

Maybe not the best science fiction book of all times, but it left a mark on my memory... and curious things like this name have stayed there since when I was a kid avidly reading everything that fell on his hands :-)

-- EDIT: Link to the book


I see a statically-typed jit-compiled python fork coming.


Anyone considering using type hints should listen to this talk: https://www.infoq.com/presentations/dynamic-static-typing/

I personally think it's mostly a waste of time to do type hinting for the purpose of catching errors in a strongly typed language like Python. Type errors just aren't practically a problem in dynamic languages. Doing types for performance is a great reason to do it, though.


I've been on teams at multiple companies that have used type annotations for Python. Developers have generally loved adopting type annotations because it (1) makes the code easier to understand (2) makes the code easier to refactor (3) improves integration with IDEs and (4) catches real bugs.

I disagree that type errors "aren't practically a problem". NoneType errors and AttributeErrors turn up all the time in Python.


Clearly didn't watch the talk then. He found that about 1-2% of errors in real world projects were type-related errors.


[40 minutes into the talk]: Looks like the study scanned 3.6 million github issues across 1.7 million repositories and looked for the number of bugs that were TypeError, AttributeError, or NameError and found it was 2.7% of issues.

I'm not a fan of this kind of methodology, because there are so many different use cases for github issue tracker (including feature requests, documentation requests, etc.) that I think the denominator here is overestimated. I'd rather have a study that looked at 1000 issues in depth with a rigorous rubric than one that grepped through millions of issues.

Also, looking only at the issues doesn't count the ones that were caught in development or testing. I like the notion of "moving your bugs to the left"[1] and would much rather find these type errors at build time than later.

Finally as I said in my other comment, avoiding type errors is not the only benefit of type checking. Making code easier to understand and refactor (including programmatic refactoring) are other benefits that are not captured only by counting bugs.

[1] https://samwho.dev/blog/move-your-bugs-to-the-left/


Fwiw this absolutely doesn't match my experience with pytype, both on my own work and, as I understand it, "at scale".


Ah yes... good old anecdotal evidence.


The org I'm in regularly publishes peer reviewed papers on engineering productivity (including on this particular subject!). It's far less anecdotal than a random talk by a random dude.


Could you kindly link to one of those papers?


https://storage.googleapis.com/pub-tools-public-publication-... for ane example not directly related to python (a migration from stronger than python to even stronger caught some, though a small number of errors).

I've also written about this publicly before, e.g. https://mail.python.org/archives/list/typing-sig@python.org/..., where I found a number of errors by tweaking pytype in a way to make it stronger. It's difficult to quantify what percentage of bugs would have been found anyway, but pretty much any time the type systems I work with improve, it uncovers new bugs.


I got around to watching the entire talk. It's not convincing to me. The presentation tacitly assumes that the only benefit to type systems is catching type errors and ignores the benefits to code readability and tooling. It also assumes that time spend developing and time spend debugging are fungible and I find that a bit simplistic; I would gladly trade debugging time for development time, even if the ratio is uneven. Finally, it doesn't even talk about the runtime performance penalty that dynamic languages typically incur.

Aside: It's worth commenting more on "code readability" because it cuts both ways. It can absolutely be the case that a complex, manifest type system can be a hindrance to understandably and productivity due to the "noise" of all the types that need to be written. I think struggling with C++ and (to a lesser extent) Java typing is part of the reason the industry really embraced dynamic languages in the 2000s. Python and Ruby were like a breath of fresh air. But eventually we built large systems with these languages and discovered the pain that comes from having no type-safety.

The trend I've seen in the last decade is to embrace type inference, with explicit type declarations on function signatures and otherwise only when needed for disambiguation. To me, this is the sweet spot, giving the benefits of static typing with much of the cleanliness and concision of dynamic languages.


I have to really question how the study was conducted if only 1-2% of python errors were considered type errors. Even if the only type error you consider is None vs not None, you'd get more than that. Certainly those errors account for more than 1% of the errors I see in my own professional experience using Python. I'm curious what his reasoning was so I'll watch the talk, but there's something screwy there.


It's a good talk even if just to learn more about types. It's not even specifically about python.

The result might be surprising, but those are the most interesting results! I note that, so far, nobody has countered this with any evidence, only anecdotes and "surely not!"


Fixing 1-2% of the errors in real world projects is nice, isn’t it? Not to mention catching the non real world errors before even running any tests.


I agree with you that the benefits of static typing are sometimes greatly exaggerated. But I also think that using type hints and type checkers in Python isn't quite the same thing as static typing.

For starters, type checking can't actually guarantee you won't have type errors at run time. Because, unlike in a statically typed language, in Python, anyone can always choose to just not use type hinting. Whenever that happens, as far as the type checker is concerned, anything goes.

But type hints are very useful as hints. They help with editor tooling, which can make it easier to navigate an unfamiliar codebase. They provide extra information that makes the code easier to read. And they give me an opt-in form of type linting that allows me to set up regions of code where I don't have to take quite so much personal responsibility for ensuring that arguments are compatible with parameters. In short, it's not a correctness prover; it's an energy saver.


> I agree with you that the benefits of static typing are sometimes greatly exaggerated.

For large, multi-developer projects, it is impossible to exaggerate the benefits of static typing.


I don't like the term "type hints" because typecheckers like mypy are genuinely proving type correctness. Yes, if you don't annotate part of your program then you can get a type error in that part of the program, likewise, if you pass a value of the wrong type, you can get a type error. But if you are using a typechecker, you are guaranteed that if your inputs are well-typed, then you won't have a type error, which is a stronger guarantee than "hints" implies.


I like the term "type hint" because that really is exactly what they are.

Typecheckers like mypy are (1) optional, and (2) are only as good as the type hints themselves. Unlike with a language that's actually statically typed, the relation of the type annotations to the actual types of the data operates largely on the honor system, so the type checking is more a validation of internal consistency than full-on static type safety. Which is fine, and well within Python's "We're all adults here" ethos. It's just that it's still not anywhere near the level of rigor you get out of the type checker in a language like OCaml.


It's really not the honor system. If you verify with a type checker, you are proving that various type errors are impossible, provided that the caller respects the type system. The rigor is exactly the same, it's just that the type system allows for "gradual typing" so that it doesn't need to be strict as in a fully-typed language.


It's not just about type errors. (Good) autocomplete and documentation are only available when types are either explicitly labeled or correctly inferred. It's important that I be able to 1. type in just the first few letters of a method name and press <tab> to complete it, and 2. hover over a method's name and get docs for the method. Both of these are only reliable if the type of the caller is known.


But we're commenting on a type checker which implies this is being done to catch errors.


It's a problem the moment it has to interact with the outside world, especially DBs/serialization/... really any kind of I/O.


So Python can't do IO? Django doesn't exist? What are you talking about exactly?


I'm talking about type safety. Types matter, a lot, and python is a PITA to use without a system like pyre.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: