Ducktyping vs Interface Johannes Rudolph 17th April, 2007 08:32 (UTC)

I don't want to start a new static-vs.-typed discussion but isn't it like this:

When you use duck typing you rely only on the method names: a method name designates one specific function. This is the contract. But what about ambiguities? ie run() might mean everything. Perhaps you can infer what is meant by 'run' looking at the context but sometimes you can't tell.

So there are interfaces. They group operations belonging to a specific concern into a logical group which can then be documented. If you provide an implementation to that interface you have to fulfill the contract. The users of the interface can now first check if an object provides the needed group of services (that is: implements this interface) and then may call operations on it.

That's not static typing. That's only grouping operation into a logical group. You might do this at runtime as well. I think that's a much clearer model than just relying on a unsharp naming scheme.

That's really a very often used principle. It's base of the Microsoft COM (component object model) which is one fundamental principle the Windows UI is build upon. Another popular implementation is XPCOM which is the base of Mozilla and Firefox.

An eye-opener for this aspect of OOP was Don Box' book 'COM' for me. I can only recommend this book even if much of the content is about the Microsoft specific implementation.

COM narrows OOP down to this notion of objects which fulfill a certain contract. You can dynamically query an object if it does so (QueryInterface). There is no multiple inheritance (problem) in COM since there are no classes and therefore no code inheritance.

I think that's the important point: You may try to solve different problems with OOP: 1.) The problem of external interface specification: Does my object fulfill a contract? Or: Has my object the requested functionality? 2.) The 'internal' problem of 'How can I reuse and extend the code of specific objects and classes?' This is where multiple inheritance becomes important because sometimes you want to incorporate functionality from multiple resources.

J

Ducktyping vs Interface Kirit Sælensminde 17th April, 2007 14:12 (UTC)

Johannes, thanks for the post.

Johannes Rudolph said

I don't want to start a new static-vs.-typed discussion but isn't it like this:

When you use duck typing you rely only on the method names: a method name designates one specific function. This is the contract. But what about ambiguities? ie run() might mean everything. Perhaps you can infer what is meant by 'run' looking at the context but sometimes you can't tell.

The problem you introduce is one of name clashes. Many dynamic languages lack much sophistication when it comes to these. Interfaces are important because the interface name (and its position within any namespaces) acts to extend the message name in a sane way, much like namespaces help us to avoid name clashes with class names.

Most languages though only allow the interface name to be used to disambiguate message names in certain situations making the whole thing less useful than it could be. More importantly hardly any allow the interface name to be used to help disambiguate the method names.

So there are interfaces. They group operations belonging to a specific concern into a logical group which can then be documented. If you provide an implementation to that interface you have to fulfill the contract. The users of the interface can now first check if an object provides the needed group of services (that is: implements this interface) and then may call operations on it.

That's not static typing. That's only grouping operation into a logical group. You might do this at runtime as well. I think that's a much clearer model than just relying on a unsharp naming scheme.

Indeed. Static typing is something completely different, but what that is depends on exactly what you mean by both “static” and “type”. The answers to both of these can vary a surprising amount, and in any case “static” and “dynamic” are two ends of a continuum. There are all sorts of interesting places between them. Whether or not there is static typing involved depends on other things and is largely orthogonal to the issue of the use of interfaces anyway.

I think you are probably right in your analysis of contract. If the language allows that the message be sent in the context of a given interface and it knows which interfaces are available you get some guarantees that you don't get where the language doesn't know. How useful these guarantees are in practice is a matter of some debate (there are still all sorts of run-time failure modes many analogous to the ones in fully dynamic languages).

That's really a very often used principle. It's base of the Microsoft COM (component object model) which is one fundamental principle the Windows UI is build upon. Another popular implementation is XPCOM which is the base of Mozilla and Firefox.

COM is used a huge amount other than for just UI. It has a fascinating, rich and subtle object model.

An eye-opener for this aspect of OOP was Don Box' book 'COM' for me. I can only recommend this book even if much of the content is about the Microsoft specific implementation.

I've not come across the book. I'll have a look out for it. I should understand COM better than I do, especially as I write COM components (actually normally I write software that writes COM components, but that's another story).

COM narrows OOP down to this notion of objects which fulfill a certain contract. You can dynamically query an object if it does so (QueryInterface). There is no multiple inheritance (problem) in COM since there are no classes and therefore no code inheritance.

The problems of multiple inheritance tend to revolve around attributes rather than methods (but not exclusively). This is why Java interfaces aren't allowed them.

I think that's the important point: You may try to solve different problems with OOP: 1.) The problem of external interface specification: Does my object fulfill a contract? Or: Has my object the requested functionality? 2.) The 'internal' problem of 'How can I reuse and extend the code of specific objects and classes?' This is where multiple inheritance becomes important because sometimes you want to incorporate functionality from multiple resources.

It's nice to come across somebody who understands that inheritance is about code reuse more than it is about type checking :-)


To join in the discussion you should register or log in