More over, with REPLs it's trivial to test a function for it's return
type with different inputs
It's not trivial. It's not trivial at all. It's only trivial to do this for trivial functions.
For instance, you could trivially define a function where the return type depends entirely on the input type.
getAnswer(v) {
return v.answer
}
In this case, getAnswer
doesn't really have a single return type. There is no test you can ever write that calls this with a sample input to learn what the return type is. It will always depend on the actual argument. At runtime.
And this doesn't even include functions that, e.g., perform database lookups. Or do things based on user input. Or look up global variables, which are of course of a dynamic type. Or change their return type in random cases. Not to mention the need to test every single individual function manually every single time.
getAnswer(x, y) {
if (x + y.answer == 13)
return 1;
return "1";
}
Fundamentally, proving the return type of the function in the general case is literally mathematically impossible (Halting Problem). The only way to guarantee the return type is to restrict the input so that answering this question does not fall under the domain of the Halting Problem by disallowing programs that are not provable, and this is what static typing does.
As an addition, as functions are declared with type funcname()...,
whitout knowing type you will have to search over each line in which
the function is called, because you only know funcname, while in
Python and the like you coud just search for def funcname or function
funcname which only happens once, at the declaration.
Statically typed languages have things called "tools". They are programs that help you do things with your source code. In this case, I would simply right click and Go To Definition, thanks to Resharper. Or use the keyboard shortcut. Or just mouse over and it will tell me what the types involved are. I don't care in the slightest about grepping files. A text editor on its own is a pathetic tool for editing program source code.
From memory, def funcname
would not be enough in Python, as the function could be re-assigned arbitrarily. Or could be declared repeatedly in multiple modules. Or in classes. Etc.
and you will still have to return to the line in which it's declared
using the search function of your text editor to check it.
Searching files for the function name is a terrible primitive operation that should never be required. This represents a fundamental failure of your environment and tooling. The fact that you would even consider needing a text search in Python is a massive point against Python.
Best Answer
Original tweeter here. :)
First of all, I'm somewhat amused/shocked that my tweet is being taken so seriously! If I had known it was going to be this widely disseminated, I would have spent more than 30 seconds writing it!
Thiago Silva is correct to point out that "static" and "dynamic" more accurately describe type checking, rather than type systems. In fact, it isn't really accurate to say that a language is statically or dynamically typed, either. Rather, a language has a type system, and an implementation of that language might enforce the type system using static checking, or dynamic checking, or both, or neither (though that would not be a very appealing language implementation!).
As it happens, there are certain type systems (or features of type systems) which are more amenable to static checking, and there are certain type systems (or features of type systems) which are more amenable to dynamic checking. For example, if your language allows you to specify in the text of a program that a particular value must always be an array of integers, then it's reasonably straightforward to write a static checker to verify that property. Conversely, if your language has subtyping, and if it permits downcasting, then it's reasonably straightforward to check the validity of a downcast at runtime, but extremely difficult to do so at compile time.
What I really meant by my tweet is simply that the vast majority of language implementations perform some amount of dynamic type checking. Or, equivalently, the vast majority of languages have some features that are difficult (if not impossible) to check statically. Downcasting is one example. Other examples include arithmetic overflow, array bounds checking, and null checking. Some of these can be statically checked in some circumstances, but by and large, you'd be hard-pressed to find a language implementation that doesn't do any checking at runtime.
This is not a bad thing. It's just an observation that there are many interesting properties that we would like our languages to enforce, and that we don't really know how to check statically. And it's a reminder that distinctions like "static types" versus "dynamic types" are not nearly as clear-cut as some people would have you believe. :)
One final note: the terms "strong" and "weak" aren't really used in the programming language research community, and they don't really have a consistent meaning. In general, I've found that when someone says that a language has "strong typing" and some other language has "weak typing", they're really saying that their favorite language (the one with "strong typing") prevents them from making some mistake that the other language (the one with "weak typing") doesn't -- or conversely, that their favorite language (the one with "weak typing") allows them to do some cool thing that the other language (the one with "strong typing") does not.