Java's Interface and Haskell's type class: differences and similarities?
While I am learning Haskell, I noticed its type class, which is supposed to be a great invention that originated from Haskell.
However, in the Wikipedia page on type class:
The programmer defines a type class by specifying a set of function or constant names, together with their respective types, that must exist for every type that belongs to the class.
Which seems rather close to Java's Interface to me (quoting Wikipedia's Interface(Java) page):
An interface in the Java programming language is an abstract type that is used to specify an interface (in the generic sense of the term) that classes must implement.
These two looks rather similar: type class limit a type's behavior, while interface limit a class' behavior.
I wonder what are the differences and similarities between type class in Haskell and interface in Java, or maybe they are fundamentally different?
EDIT: I noticed even haskell.org admits that they are similar. If they are so similar (or are they?), then why type class is treated with such hype?
MORE EDIT: Wow, so many great answers! I guess I'll have to let the community decide which is the best one. However, while reading the answers, all of them seem to just say that "there are many things typeclass can do while interface cannot or have to cope with generics". I cannot help but wondering, are there anything interfaces can do while typeclasses cannot? Also, I noticed that Wikipedia claims that typeclass was originally invented in the 1989 paper *"How to make ad-hoc polymorphism less ad hoc", while Haskell is still in its cradle, while Java project was started in 1991 and first released in 1995. So maybe instead of typeclass being similar to interfaces, its the other way around, that interfaces were influenced by typeclass? Are there any documents/papers support or disprove this? Thanks for all the answers, they are all very enlightening!
Thanks for all the inputs!
Solution 1:
I would say that an interface is kind of like a type class SomeInterface t
where all of the values have the type t -> whatever
(where whatever
does not contain t
). This is because with the kind of inheritance relationship in Java and similar languages, the method called depends on the type of object they are called on, and nothing else.
That means it's really hard to make things like add :: t -> t -> t
with an interface, where it is polymorphic on more than one parameter, because there's no way for the interface to specify that the argument type and return type of the method is the same type as the type of the object it is called on (i.e. the "self" type). With Generics, there are kinda ways to fake this by making an interface with generic parameter that is expected to be the same type as the object itself, like how Comparable<T>
does it, where you are expected to use Foo implements Comparable<Foo>
so that the compareTo(T otherobject)
kind of has type t -> t -> Ordering
. But that still requires the programmer to follow this rule, and also causes headaches when people want to make a function that uses this interface, they have to have recursive generic type parameters.
Also, you won't have things like empty :: t
because you're not calling a function here, so it isn't a method.
Solution 2:
What is similar between interfaces and type classes is that they name and describe a set of related operations. The operations themselves are described via their names, inputs, and outputs. Likewise there may be many implementations of these operations that will likely differ in their implementation.
With that out of the way, here are some notable differences:
- Interfaces methods are always associated with an object instance. In other words, there is always an implied 'this' parameter that is the object on which the method is called. All inputs to a type class function are explicit.
- An interface implementation must be defined as part of the class that implements the interface. Conversely, a type class 'instance' can be defined completely seperate from its associated type...even in another module.
In general, I think its fair to say that type classes are more powerful and flexible than interfaces. How would you define an interface for converting a string to some value or instance of the implementing type? It's certainly not impossible, but the result would not be intuitive or elegant. Have you ever wished it was possible to implement an interface for a type in some compiled library? These are both easy to accomplish with type classes.
Solution 3:
Type classes were created as a structured way to express "ad-hoc polymorphism", which is basically the technical term for overloaded functions. A type class definition looks something like this:
class Foobar a where
foo :: a -> a -> Bool
bar :: String -> a
What this means is that, when you use apply the function foo
to some arguments of a type that belong to the class Foobar
, it looks up an implementation of foo
specific to that type, and uses that. This is very similar to the situation with operator overloading in languages like C++/C#, except more flexible and generalized.
Interfaces serve a similar purpose in OO languages, but the underlying concept is somewhat different; OO languages come with a built-in notion of type hierarchies that Haskell simply doesn't have, which complicates matters in some ways because interfaces can involve both overloading by subtyping (i.e., calling methods on appropriate instances, subtypes implementing interfaces their supertypes do) and by flat type-based dispatch (since two classes implementing an interface may not have a common superclass that also implements it). Given the huge additional complexity introduced by subtyping, I suggest it's more helpful to think of type classes as an improved version of overloaded functions in a non-OO language.
Also worth noting is that type classes have vastly more flexible means of dispatch--interfaces generally apply only to the single class implementing it, whereas type classes are defined for a type, which can appear anywhere in the signature of the class's functions. The equivalent of this in OO interfaces would be allowing the interface to define ways to pass an object of that class to other classes, define static methods and constructors that would select an implementation based on what return type is required in calling context, define methods that take arguments of the same type as the class implementing the interface, and various other things that don't really translate at all.
In short: They serve similar purposes, but the way they work is somewhat different, and type classes are both significantly more expressive and, in some cases, simpler to use because of working on fixed types rather that pieces of an inheritance hierarchy.