True, but I think part of this is about shaping behavior, and about self-discipline. And perhaps also the cognitive bias that comes from knowing one's own program well. A program I wrote always seems more obvious to me than it does to others. It seems to me that the mind, while aware of gaps in knowledge between ourselves and others, cannot fully compensate for this. It's like Hofstadter's law ("It always takes longer than you expect, even when you take into account Hofstadter's Law.")

So I don't know if I fully trust myself to decide which type annotations are obvious up front. Though maybe I'm just used to this way of working. I'm not aware of many solid studies of the differences that move far beyond personal preference. Especially studies that measure the performance of teams over time (vs virtuoso performances). Also, how happy would you be as the maintainer of a codebase if a new guy came along and submitted a pull request which was purely the addition of an already-inferred type?

Type declarations tend to be pretty low effort for me, these days. The way that I write code in Eclipse works like this:

// I type out this part
f(x)

Then I invoke auto-complete and ask Eclipse to automatically assign the expression to a new local variable or field. If f() doesn't exist, I might ask it to create that method. It will infer part of the signature from the type of x. Once I write the method, I can auto-complete its return type. Or if the method exists, taking the type of the variable "x", it can suggest that I probably want "x" as the parameter. I just type "f(" and invoke auto-complete. Anyway, once I ask it to assign to a variable, I end up with something like:

Foo foo = f(x);

I'm given a choice of common variable names based on the type in question which are easy to choose between with good defaults. So most of the time I'm sort of minimally describing or hinting at what I want, and the IDE guesses extremely well what I mean -- better than a compiler ever could, because it's allowed to make multiple guesses and be wrong -- and then I capture or snapshot that by saving it as text.

The type inference is actually just as present as in the other languages, it's just happening up front at editing time, rather than at compile time. And these benefits don't only apply during original composition. If I edit the method f() and change its return type, I can just as easily auto-complete (or more broadly, use automated refactoring for) the change to the type declaration for the "foo" variable.

Maybe if you're a programmer of dynamic languages or heavily type-inferred languages, this will seem like "much ado about nothing". "Isn't it the same in the end?" The difference to me is that it's all there in the text, and on the screen, by default; and it's all comprehensible even without an IDE and without an understanding of all of the types involved. I still drop out of the IDE surprisingly often to read code at the command line or in a web browser.

I can also see where the alternative view is coming from though that, if I don't have to define the type of variable "foo", then I don't have to change the text when "f()" changes. I would support a "var" keyword in Java, and agree the problem is really about when type inference goes too far. But I see the effort of changing "foo" as much less of a problem than easily and frictionlessly understanding what the code means, immediately when reading it, with minimal reliance on context.

I would be interested to take a look at a large F# program and see how easily I can figure it out.