Why ‘type’ matters?
It matters in OOP if you want to write a framework or develop a OO system that is truly extensible. Good news for new OO programmers: a) It matters to you if you want to really understand and appreciate polymorphism b) It also helps you to answer the world famous interview question: What is the difference between an abstract class and an interface?
Ignore java interface for now. I mean the java syntax: public interface MyInterface{… (I wonder the optimism exhibited by authors who try to explain interfaces and polymorphism with MyInterface or XInterface).
Every object is of some type: Let me look around. A House is a type of Building. A Chair is a type of Furniture. A Wireless keyboard is a type of Keyboard. A Keyboard is a type of interface (I mean Peripheral interface..just kidding). A cell phone is a type of Phone (You just thought of a Phone super-class and CellPhone subclass, didn’t you?).
Type is a way to generalize the properties of one or more objects. For example, you can make and receive calls on any type of Phone. You can type characters in a text editor using any type of Keyboard. When you check an object instanceof X in Java, you are truely checking if the object is typeof X. If the check returns true, you can assign the object to a variable of type X (!) and invoke a method defined in X. The object accepts all requests for the operations defined in X and it’s super types. So, a type essentially indicates a particular interface of an object. An object’s interface defines the set of operations that can be executed on it. OO books refer to the process of invoking an object’s method as ’sending a message’ or ’sending a request’ . You can access/invoke an object only through it’s interface. An object can be of many types and many objects can be of same type (polymorphism and substitutability). A client object(caller) doesn’t know anything about an object itself but it’s interface.
If you look at the above paragraph carefully, we have already touched lot of the topics in OOP like Objects, Interfaces, Types, Interface inheritance, Polymorphism – Dynamic Binding – Substitutability etc. We haven’t talked about the java interface yet. In fact we haven’t talked about even classes yet. Many people think a class is the starting point of Object-Oriented Programming. Had that been true, it would have been called Class-Oriented Programming.
A class comes into picture only during implmentation of an object. An object’s class defines the template of how it’s object would look like - by specifying the internal state and operations that could be invoked. How is an object’s class related to its type?
Thinking in Java (Bruce Eckel): Every object has a type. Using the parlance, each object is an instance of a class, in which “class” is synonymous with “type.” The most important distinguishing characteristic of a class is “What messages can you send to it?”. All objects of a particular type can receive the same messages. An object has an interface. The requests you can make of an object are defined by its interface, and the type is what determines the interface.
Design patterns (GoF): There’s a close relationship between class and type. Because a class defines the operations an object can perform, it also defines the object’s type. When we say that an object is an instance of a class, we imply that the object supports the interface defined by the class.
Type is important in OOP because that is what allows you to substitute an object with another of same type. The client objects (caller) access the object through the interface defined by its type. For example, a CellPhone and CordlessPhone are different types of Phone that use entirely different technologies. However you could use either of them the same way without having to know about their implementations because they both are of type Phone. You can use a cell phone in place of a cordless phone to make calls and vice versa.
You would be forming a hierarchy of types if you include the interface of one into another. This is known as sub-typing. A wireless keyboard is a type of keyboard which is in turn a type of peripheral device. In this case, the wireless keyboard includes the interface of Keyboard which includes the interface of PeripheralDevice type. Remember only the interface (set of operations) is included, not the implementation. That is, there could be different implementations of PeripheralDevice (mouse, UBS hard-drive etc). Similarly there could be different implementations of Keyboard (diff brands, standard/internet keyboards, Japanese etc) and wireless keyboard. The wireless keyboard supports all operations defined by it’s own type + Keyboard type + PeripheralDevice type. This is interface-inheritance with which we inherit only the interface defined by the super type.
Now comes the question of how to define a type in Java. As we have seen earlier, an object’s own class itself defines its type. When you extend a class from another, that is with class-inheritance, you are actually inheriting both the type and implementation of the super class. An object of the new class obviously supports the operations defined in its super class . Take the classic java.lang.Object.toString() method. Every object in Java supports this method because it is a type of java.lang.Object. A button object can receive mouse events through a listener because it is a type of java.awt.Component. It can be added to a Frame because it is a type of Window which is a type of Container. “abc” is an object which is a type of String so you could invoke length() operation. It is also a type of java.lang.Object so a thread could wait() on it. It is also a type of Comparable so you can compare it with “def”…Isn’t Comparable a java interface?
Java allows you to define types as pure interfaces (now we are talking about java interfaces). A pure interface defines only the operations and no implementation. It just defines a type so that any object that implements the interface can be treated the same way. A pure abstract class is exactly same as an interface because it too just forms a type. The difference between an abstract class and interface makes sense only when the class is partially abstract in which case one or more of its methods are concrete. A subclass in this case inherits the implementation concrete methods defined in the super class. Let’s stop here: When a class implements an interface, you are doing interface-inheritance. You are making the class of the interface type. When a class extends another class, you are doing both class-inheritance (or implementation inheritance) and interface-inheritance.
You can mix and match these features however you like. For example, if you ever written an applet, you extend from java.awt.Applet. And, if you want to start a thread (normally a scrolling ticker:) you make your class implement java.lang.Runnable. In this case, your class has two types: Applet and Runnable. The applet container knows your applet object through Applet interface whereas the Runnable interface is used in turn by the Thread object you start. Or considering a simple class MyThread class extending Thread, Thread is a type of Runnable and MyThread is a type of Thread. In the former case we inherit only the interface defined by the type (run() method) whereas in the latter we inherit interfaces of both Thread and Runnable + implementation of Thread class. Or considering an instance of ArrayList, it is a type of List (as with LinkedList), a type of Collection (as with HashSet), a type of Serializable (as with String). By extending AbstractList, it inherits the interfaces defined by List and Collection in addition to lot of functionality (implementation inheritance).
When people say “Program to interface, not implementation”, they mean the interface defined by the object’s type, not an equivalent java interface. You program to an object’s interface as long as your assigned type is a super-type that can potentially have multiple implementations. This allows you to configure or choose respective implementation at runtime.
InputStream is = …;
int data = is.read();
Connection c = …;
Statement s = c.createStatement();
In the first example, we use the interface defined by the abstract class java.io.InputStream. You can use FileInputStream or ByteArrayInputStream or any other types of InputStream the same way. In the second example, we use the interface defined by the java interface java.sql.Connection. You could use OracleConnection or SQLServerConnection or any other types of Connection the same way. This substitutability is a key feature of any OO system.
Let’s check on some common statements made about abstract classes and interfaces.
- A class can extend only one abstract class whereas it can implement multiple interfaces: This statement doesn’t tell anything about what’s there in the abstract class. People normally mean partially implemented abstract class here in which case, it is both type and class (implementation) inheritance. If it is a pure abstract class, then it is a pure interface inheritance. By implementing multiple interfaces, we make the object of multiple types. Without the notion of type or object’s interface, this statement is unclear.
- Java doesn’t support multiple-inheritance, hence we have interfaces: Again, by multiple-inheritance, people mean ‘class-inheritance’. However there is no reuse of implementation when you implement an interface. I think it has to read “A java interface is the best candidate to represent a type. In order to design a class that can have many types, we make it implement multiple interfaces”. Example: ArrayList class and Collection and Serializable interfaces.
So, what type are you?
Note: I will try to improve the content of this post after some time. I would like to have a fresh look.
-Raj Radhakrishnan
2 comments so far
Leave a reply
A few points -
1) I was still under the impression that “Program to interface, not implementation” means a C# / Java interface.
2) Don’t you think OO is broken because it gives me two ways to define a type – an interface and a class? If the only way to define a type was an interface, I think more than 50% of the problems would’ve been solved.
3) Related to 2 above, I found an example (on the internet), where the class implemented an interface explicitly (in C#). So when you explicitly implement an interface in C#, the client cannot write – ShippingStrategy ss = new ShippingStrategy();
but he’s forced to write -
IShippingStrategy is = new ShippingStrategy();
Again, if this was the only way to implement interfaces, most beginners would get it right.
[ Most likely there is no equivalent in Java for "explicit interface implementation" so please see this for more information on what it is -
http://www.25hoursaday.com/CsharpVsJava.html ]
4) I came across these terms implementation vs. interface inheritance in a COM book. COM was based on interface inheritance, but it still failed
[obviously problems would be elsewhere]
5) I am thoroughly confused by “In order to design a class that can have many types, we make it implement multiple interfaces”, because as per Single Responsibility Principal, your class should do only one thing, in which case I believe, a class should implement only one interface. So why is it that there are so many classes in Java / C# which extend a class and implement many interfaces? Please clarify the difference between – a class can have many types and it should do only one thing.
Nice post again
#1)
I have to truely appreciate your openness. You are not alone, that’s what is the understanding of most people. I too was thinking the same way for a long time.
I will reply for your other questions soon.