Now, many languages with formal interfaces (e.g., Java) are strongly typed, and they treat interfaces as types. Thus, for example, classes have to declare up front what interfaces they implement. That doesn't fit well with the flexible attitude of a duck-typed language. However, if interfaces were just collections of method signatures that could be tested against objects at runtime, that would be perfectly compatible with duck typing.
Languages like Modula-3 that use structural type equivalence sort of do this even in a strongly-typed system. Sort of.
Interfaces are useful in defining what an implementor must provide, but an example implementation does this as well.
Also, if it helps, just think of the impl as an interface with a default behaviour that should be overriden ;)
If this is too forgiving, then we can even have the impl methods throw errors ("override me!") and simulate an interface.
someMethod
self subclassResponsibility
and then use the realize class refactoring on a subclass to generate stubs for all methods I must implement, just like an interface.What I was trying to get to: if you accept the existence of single-method ducktypes (like "things that have a walk() method" oder "things that have a quack() method"), then by intersecting these concepts, you arrive at things just like interfaces, whether you call them interfaces or not. If you want the pond system to work with your two-legged bird-sound robot, you perform the same mental steps as when implementing an interface. Hence, ducktypes could be seen as interfaces without an instanceof-operation.
For example, a hash-based collection might require that all its members implement an equality method and a hash method. Typically in Ruby you test this by just waiting for one of those method calls to blow up somewhere in the hash table code. Instead, you could test "acts_like?(Hashable)" -- meaning "reaponds_to?(:=) && responds_to?(:hash)" -- on insertion. Then you could give a nice, meaningful error message at a nice point in the code.
Note that this has nothing whatsoever to do with is_a?, which is the important difference between this and type-based interfaces as in Java.
What mechanism would enforce the contract anyway? The best you could hope for would be a runtime error thrown when the interpreter detected the incompatibility, and you can do that manually now (I do it frequently to imitate abstract classes).
class IAnimal
def growl
raise
end
end