If I understand your question correctly, the answer boils down to this:
TLDR
The reason for having things like abstract classes and interfaces/protocols in a dynamic language like Objective-C are mainly simplicity and cleanliness of code.
The longer version
As cool as duck-typing is, it's actually a huge hassle if you cannot make any assumptions on the type of an object:
every respondsToSelector:
line in your code messes it up. It adds noise that obfuscates what you are actually trying to accomplish for little to no benefit.
Besides, it's shit-work.
So if you provide an API contract by loosing some dynamism, using a more statically typed model it's almost always a win:
- Replacing multiple
respondsToSelector:
methods with a single conformsToProtocol:
is a win.
- Having a succinct and clear listing of the necessary methods in the protocol definition is a win. (Writing that definition in and of itself is shit-work as well, but it keeps you from doing more shit-work in a number of places, so that's tolerable.)
- Based on that, having the compiler warn you if you omitted implementing any one of those methods is a huge win.
- And: Not having to write a single
respondsToSelector:
or conformsToProtocol:
message at all, because the compiler can now warn and tell you where you messed up, is the biggest win of all.
If you can go further than that by providing a common foundation of actual implementation, creating an abstract class might be an even bigger win (probably not so useful in the context of delegation...) — after all, repeating yourself in implementation is the worst case of shit-work, as every change will result in more shit-work to keep things consistent.
So yes, dynamism is a cool and useful thing to have, as it allows you to pull off all kinds of fun tricks. But in practice, getting rid of some of that (where appropriate) can make your life much easier and keep you from doing shit-work — like writing respondsToSelector:
.
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
In my experience, it is simply a language that uses static typing with a Structural Type System. It essentially applies the "walks like a duck, talks like a duck" check at compile type so that the programmer doesn't need to provide annotations to specifically sub-type things.
This has a very large benefit when you're trying to glue two (or more) libraries together. With a nominative type system, if you had some interface in one library and an object in the other, they don't know about one another and can't sub-type - even if the object satisfies the interface's requirements. Structural typing makes that okay.
Making the language static just means that the compiler does that check at compile time, giving you an error early (and clearly) when that object doesn't really satisfy the interface.
There are a few esoteric languages that do this, but most structurally typed languages are also dynamically typed and almost all nominative typed languages are also statically typed.