Static typing lends itself to static analysis and other defensive programming practices that are easy to enforce at compile-time (such as design by contract.) A lot of bugs and design errors die long before erroneous code hits source control as a result - definitely not all of them, but many of them.
The best compromise between static typing and dynamic typing, IMHO, is what C# (and later generations of C++) do: implicit typing via the VAR keyword.
You can't implicitly type the members of an object or the arguments of a function, but you can implicitly type variables in local scope. This is how C# is able to support anonymous types and functions so easily - implicit typing abstracts away the gangly looking static objects that are produced by LINQ queries and the like.
Implicit typing makes it very easy to refactor large blocks of statically typed code without compromising the benefits of static typing. So you get some of the flexibility of dynamic typing with the predictability of static typing.
Realistically - you don't utterly redefine the type of objects at runtime very often in production code even with dynamic languages, so you don't lose much with implicit typing.
>You can't implicitly type the members of an object or the arguments of a function
That was due more to architectural issues in the C# compiler than any principled reason. C#'s type inference is extremely weak and incomplete and is a poor example of "getting it right".
I'm failing to imagine a scenario where implicitly typing either of these would benefit me as the developer - having those elements remain statically typed seems like "the right thing to do" given their role in defining public code contracts. Could you help me understand why this is a bad thing?
Your point about defining a public interface is separate. If you have a specific API that you cannot break, then feel free to type it out all you want. If you feel a piece of code is confusing or unclear without an annotation, go ahead and add it.
For the majority of code, having to specify the types is an exercise in verbosity, nothing more. Unless you're only writing public libraries with no internal implementation, I don't see how there's not a scenario.
I agree that doing that type of inference would be convenient - I deal with a lot of nested generics like that on daily basis.
But this is just syntactic sugar, and the var keyword already takes care of the left-hand operand in this equation. Generic functions also do a reasonably good job of type inference under this set of circumstances, although I've found that generic delegates and lambdas not so much.
The best compromise between static typing and dynamic typing, IMHO, is what C# (and later generations of C++) do: implicit typing via the VAR keyword.
You can't implicitly type the members of an object or the arguments of a function, but you can implicitly type variables in local scope. This is how C# is able to support anonymous types and functions so easily - implicit typing abstracts away the gangly looking static objects that are produced by LINQ queries and the like.
Implicit typing makes it very easy to refactor large blocks of statically typed code without compromising the benefits of static typing. So you get some of the flexibility of dynamic typing with the predictability of static typing.
Realistically - you don't utterly redefine the type of objects at runtime very often in production code even with dynamic languages, so you don't lose much with implicit typing.