Search code examples
c#oophaskellinterfaceprogramming-languages

Is there any advantage in disallowing interface implementation for existing classes?


In static OOP languages, interfaces are used in order to declare that several classes share some logical property - they are disposable, they can be compared to an int, they can be serialized, etc.

Let's say .net didn't have a standard IDisposable interface, and I've just came up with this beautiful idea:

interface IDiscardable { void Discard(); }

My app uses a lot of System.Windows.Forms, and I think that a Form satisfies the logical requirements for being an IDiscardable. The problem is, Form is defined outside of my project, so C# (and Java, C++...) won't allow me to implement IDiscardable for it. C# doesn't allow me to formally represent the fact that a Form can be discarded ( and I'll probably end up with a MyForm wrapper class or something.

In contrast, Haskell has typeclasses, which are logically similar to interfaces. A Show instance can be presented (or serialized) as a string, Eq allows comparisons, etc. But there's one crucial difference: you can write a typeclass instance (which is similar to implementing an interface) without accessing the source code of a type. So if Haskell supplies me with some Form type, writing an Discardable instance for it is trivial.

My question is: from a language designer perspective, is there any advantage to the first approach? Haskell is not an object oriented language - does the second approach violates OOP in any way?

Thanks!


Solution

  • This is a difficult question, which stems from a common misunderstanding. Haskell type classes (TC), are said to be "logically similar" to the interfaces or abstract classes (IAC) from object-oriented programming languages. They are not. They represent different concepts about types and programming languages: IAC are a case of subtyping, while TC is a form of parametric polymorphism.

    Nevertheless, since your questions are methodological, here I answer from a methodological side. To start with the second question:

    does the second approach [that of extending the implementation of a class outside the class] violate OOP in any way

    Object oriented programming is a set of ideas to describe the execution of a program, the main elements of an execution, how to specify these elements in the program's code, and how to structure a program so as to separate the specification of different elements. In particular, OOP is based in these ideas:

    • At any state of its execution, a process (executing program) consists of a set of objects. This set is dynamic: it may contain different objects at different states, via object creation and destruction.
    • Every object has an internal state represented by a set of fields, which may include references to other related objects. Relations are dynamic: the same field of the same object a may at different states point to different objects.
    • Every object can receive some messages from another object. Upon receiving a message, the object may alter its state and may send messages to objects in its fields.
    • Every object is an instance of a class: the class describes what fields the object has, what messages it can receive, and what it does upon receiving a message.
    • In an object a, the same field a.f may at different states point to different objects, which may belong to different classes. Thus, a needs not to know to what class those objects b belong; it only needs to know what messages do those objects accept. For this reason, the type of those fields can be an interface. The interface declares a set of messages that an object can receive. The class specifies explicitly what interfaces are satisfied by the objects of that class.

    My answer to the question: in my opinion yes.

    Implementing an interface (as suggested in the example) outside a class breaks one of these ideas: that the class of the object describes the complete set of messages that objects in that class can receive.

    You may like to know, though, that this is (in part) what "Aspects", as in AspectJ, are about. An Aspect describes the implementation of a certain "method" in several classes, and these implementations are incorportated (weaved) into the class.

    To answer back the first question, "is there any advantage to the first approach", the answer would be also yes: that all the behaviour of an object (what messages it answers to) is only described in one place, in the class.