<p>In addition to Andreas's excellent answer, please keep in mind that type classes are meant to streamline <em>overloading</em>, which affects the global name space.  There is no overloading in Haskell other than what you can obtain via type classes.  In contrast, when you use object interfaces, only those functions that are declared to take arguments of that interface will need to worry about the function names in that interface.  So, interfaces provide local name spaces.</p>

<p>For example, you had <code>fmap</code> in an object interface called "Functor".  It would be perfectly ok to have another <code>fmap</code> in another interface, say "Structor".  Each object (or class) can pick and choose which interface it wants to implement.  In contrast, in Haskell, you can have only one <code>fmap</code> within a particular context.  You cannot import both Functor and Structor type classes into the same context.</p>

<p>Object interfaces are more similar to Standard ML signatures than to type classes.</p>

CC BY-SA 3.0
2014-04-05T10:33:31.920Z
and yet there seems to be a close relationship between ML modules and Haskell type classes. http://www.cse.unsw.edu.au/~chak/papers/DHC07.html
Steven Shaw
CC BY-SA 3.0
2012-03-07T18:08:11.030Z
2012-03-12T11:05:56.763Z
2012-03-12T11:05:56.763Z
Uday Reddy
<p>In your concrete example (with Functor type class), Haskell and Java implementations behave differently. Imagine you have Maybe data type and want it to be Functor (it is really popular data type in Haskell, which you can easily implement in Java as well). In your Java example you will make Maybe class implement your Functor interface. So you can write the following (just pseudo code because I have c# background only) :</p>

<pre><code>Maybe&lt;Int&gt; val = new Maybe&lt;Int&gt;(5);
Functor&lt;Int&gt; res = val.fmap(someFunctionHere);
</code></pre>

<p>Notice that the <code>res</code> has type Functor, not Maybe. So this makes Java implementation almost unusable because you lose concrete type information, and need to do casts. (at least I failed to write such an implementation where types were still present).
With Haskell type classes you will get Maybe Int as a result.</p>

CC BY-SA 3.0
2015-12-06T20:32:38.657Z
I think this issue is due to Java not supporting higher kinded types, and is not related to the interfaces Vs typeclasses discussion. If Java had higher kinds, then fmap could very well return a `Maybe<Int>`.
dcastro
CC BY-SA 3.0
2013-11-08T12:31:44.953Z
2013-11-08T12:31:44.953Z
struhtanov
<p>In their basic form, type classes are somewhat similar to object interfaces. However, in many respects, they are much more general.</p>

<ol>
<li><p>Dispatch is on types, not values. No value is required to perform it. For example, it is possible to do dispatch on the result type of function, as with Haskell's <code>Read</code> class:</p>

<pre><code>class Read a where
  readsPrec :: Int -&gt; String -&gt; [(a, String)]
  ...
</code></pre>

<p>Such dispatch is clearly impossible in conventional OO.</p></li>
<li><p>Type classes naturally extend to multiple dispatch, simply by providing multiple parameters:</p>

<pre><code>class Mul a b c where
  (*) :: a -&gt; b -&gt; c

instance Mul Int Int Int where ...
instance Mul Int Vec Vec where ...
instance Mul Vec Vec Int where ...
</code></pre></li>
<li><p>Instance definitions are independent from both class and type definitions, which makes them more modular. A type T from module A can be retrofitted to a class C from module M2 without modifying the definition of either, simply by providing an instance in module M3. In OO, this requires more esoteric (and less OO-ish) language features like extension methods.</p></li>
<li><p>Type classes are based on parametric polymorphism, not subtyping. That enables more accurate typing. Consider e.g.</p>

<pre><code>pick :: Enum a =&gt; a -&gt; a -&gt; a
pick x y = if fromEnum x == 0 then y else x
</code></pre>

<p>vs.</p>

<pre><code>pick(x : Enum, y : Enum) : Enum = if x.fromEnum() == 0 then y else x
</code></pre>

<p>In the former case, applying <code>pick '\0' 'x'</code> has type <code>Char</code>, whereas in the latter case, all you'd know about the result would be that it's an Enum. (This is also the reason why most OO languages these days integrate parametric polymorphism.)</p></li>
<li><p>Closely related is the issue of binary methods. They are completely natural with type classes:</p>

<pre><code>class Ord a where
  (&lt;) :: a -&gt; a -&gt; Bool
  ...

min :: Ord a =&gt; a -&gt; a -&gt; a
min x y = if x &lt; y then x else y
</code></pre>

<p>With subtyping alone, the <code>Ord</code> interface is impossible to express. You need a more complicated, recursive form or parametric polymorphism called "F-bounded quantification" to do it accurately. Compare Java's <code>Comparable</code> and its use:</p>

<pre><code>interface Comparable&lt;T&gt; {
  int compareTo(T y);
};

&lt;T extends Comparable&lt;T&gt;&gt; T min(T x, T y) {
  if (x.compareTo(y) &lt; 0)
    return x;
  else
    return y;
}
</code></pre></li>
</ol>

<p>On the other hand, subtyping-based interfaces naturally allow the formation of heterogeneous collections, e.g. a list of type <code>List&lt;C&gt;</code> can contain members that have various subtypes of <code>C</code> (although it is not possible to recover their exact type, except by using downcasts). To do the same based on type classes, you need existential types as an additional feature.</p>

CC BY-SA 3.0
2012-01-15T03:57:29.430Z
Ah, that makes a lot of sense. The type vs value-based dispatch is probably the big thing I wasn't thinking about properly. The issue of parametric polymorphism and more specific typing makes sense. I had just pulled that and subtyping-based interfaces together in my mind (apparently I think in Java :-/ ).
oconnor0
CC BY-SA 3.0
2012-01-15T04:03:28.753Z
Are existential types something akin to creating subtypes of `C` without the presence of downcasts?
oconnor0
CC BY-SA 3.0
2012-01-15T08:02:04.110Z
Kind of. They are a means for making a type abstract, i.e. hiding its representation. In Haskell, if you also attach class constraints to it, you can still use methods of those classes on it, but nothing else. -- Downcasts are actually a feature that is separate from both subtyping and existential quantification, and could, in principle, be added in the presence of the latter, too. Just as there are OO languages who don't provide it.
Andreas Rossberg
CC BY-SA 3.0
2012-01-15T08:48:20.603Z
PS: FWIW, wildcard types in Java are existential types, though rather limited and ad-hoc (which may be part of the reason why they are somewhat confusing).
Andreas Rossberg
CC BY-SA 3.0
2013-02-11T13:27:55.077Z
Would it be possible to emulate the case of type dispatch feature of typeclasses as overloaded functions in OOP? That would not be the same of course, since the function def. would be independant of the class, whereas in the typeclass, the function is mandatory, but it appears to me as possible solution.
didierc
CC BY-SA 3.0
2013-02-11T14:25:28.803Z
@didierc, that would be restricted to cases that can be fully resolved statically. Moreover, to match type classes it would require a form of overloading resolution that is able to distinguish based on the return type alone (see item 1).
Andreas Rossberg
CC BY-SA 3.0
2013-02-11T15:50:29.910Z
Ah, right, classic overloading doesn't work on return type! Thanks, I overlooked that point. Very good answer btw.
didierc
CC BY-SA 3.0
2012-01-14T10:10:58.267Z
2012-01-14T14:28:39.610Z
2012-01-14T14:28:39.610Z
Andreas Rossberg
<p>I don't think I understand type classes. I'd read somewhere that thinking of type classes as "interfaces" (from OO) that a type implements is wrong and misleading.
The problem is, I'm having a problem seeing them as something different and how that is wrong.</p>

<p>For example, if I have a type class (in Haskell syntax)</p>

<pre><code>class Functor f where
  fmap :: (a -&gt; b) -&gt; f a -&gt; f b
</code></pre>

<p>How is that different than the interface [1] (in Java syntax)</p>

<pre><code>interface Functor&lt;A&gt; {
  &lt;B&gt; Functor&lt;B&gt; fmap(Function&lt;B, A&gt; fn)
}

interface Function&lt;Return, Argument&gt; {
  Return apply(Argument arg);
}
</code></pre>

<p>One possible difference I can think of is that the type class implementation used at a certain invocation is not specified but rather determined from the environment -- say, examining available modules for an implementation for this type. That seems to be an implementation artifact that could be addressed in an OO language; like the compiler (or runtime) could scan for a wrapper/extender/monkey-patcher that exposes the necessary interface on the type.</p>

<p>What am I missing?</p>

<p>[1] Note the <code>f a</code> argument has been removed from <code>fmap</code> since given it's an OO language, you'd be calling this method on an object. This interface assumes the <code>f a</code> argument has been fixed.</p>

<pl.programming-languages><type-theory><type-systems>
Type classes vs object interfaces
oconnor0
# Type classes vs object interfaces

(Asked by: username_0 on 2012-01-13)

I don't think I understand type classes. I'd read somewhere that thinking of type classes as "interfaces" (from OO) that a type implements is wrong and misleading.
The problem is, I'm having a problem seeing them as something different and how that is wrong.
For example, if I have a type class (in Haskell syntax)
class Functor f where
  fmap :: (a -> b) -> f a -> f b

How is that different than the interface [1] (in Java syntax)
interface Functor {
   Functor fmap(Function fn)
}

interface Function {
  Return apply(Argument arg);
}

One possible difference I can think of is that the type class implementation used at a certain invocation is not specified but rather determined from the environment -- say, examining available modules for an implementation for this type. That seems to be an implementation artifact that could be addressed in an OO language; like the compiler (or runtime) could scan for a wrapper/extender/monkey-patcher that exposes the necessary interface on the type.
What am I missing?
[1] Note the f a argument has been removed from fmap since given it's an OO language, you'd be calling this method on an object. This interface assumes the f a argument has been fixed.

**Tags:** pl.programming-languages, type-theory, type-systems

---

## 3 answers

### Answer by username_5 on 2012-01-14. Score: 48 | Accepted answer

In their basic form, type classes are somewhat similar to object interfaces. However, in many respects, they are much more general.

Dispatch is on types, not values. No value is required to perform it. For example, it is possible to do dispatch on the result type of function, as with Haskell's Read class:
class Read a where
  readsPrec :: Int -> String -> [(a, String)]
  ...

Such dispatch is clearly impossible in conventional OO.
Type classes naturally extend to multiple dispatch, simply by providing multiple parameters:
class Mul a b c where
  (*) :: a -> b -> c

instance Mul Int Int Int where ...
instance Mul Int Vec Vec where ...
instance Mul Vec Vec Int where ...

Instance definitions are independent from both class and type definitions, which makes them more modular. A type T from module A can be retrofitted to a class C from module M2 without modifying the definition of either, simply by providing an instance in module M3. In OO, this requires more esoteric (and less OO-ish) language features like extension methods.
Type classes are based on parametric polymorphism, not subtyping. That enables more accurate typing. Consider e.g.
pick :: Enum a => a -> a -> a
pick x y = if fromEnum x == 0 then y else x

vs.
pick(x : Enum, y : Enum) : Enum = if x.fromEnum() == 0 then y else x

In the former case, applying pick '\0' 'x' has type Char, whereas in the latter case, all you'd know about the result would be that it's an Enum. (This is also the reason why most OO languages these days integrate parametric polymorphism.)
Closely related is the issue of binary methods. They are completely natural with type classes:
class Ord a where
  (<) :: a -> a -> Bool
  ...

min :: Ord a => a -> a -> a
min x y = if x < y then x else y

With subtyping alone, the Ord interface is impossible to express. You need a more complicated, recursive form or parametric polymorphism called "F-bounded quantification" to do it accurately. Compare Java's Comparable and its use:
interface Comparable {
  int compareTo(T y);
};

> T min(T x, T y) {
  if (x.compareTo(y) < 0)
    return x;
  else
    return y;
}


On the other hand, subtyping-based interfaces naturally allow the formation of heterogeneous collections, e.g. a list of type List can contain members that have various subtypes of C (although it is not possible to recover their exact type, except by using downcasts). To do the same based on type classes, you need existential types as an additional feature.

> **Comments:**
> **username_0**: Ah, that makes a lot of sense. The type vs value-based dispatch is probably the big thing I wasn't thinking about properly. The issue of parametric polymorphism and more specific typing makes sense. I had just pulled that and subtyping-based interfaces together in my mind (apparently I think in Java :-/ ).  
> **username_0**: Are existential types something akin to creating subtypes of `C` without the presence of downcasts?  
> **username_5**: Kind of. They are a means for making a type abstract, i.e. hiding its representation. In Haskell, if you also attach class constraints to it, you can still use methods of those classes on it, but nothing else. -- Downcasts are actually a feature that is separate from both subtyping and existential quantification, and could, in principle, be added in the presence of the latter, too. Just as there are OO languages who don't provide it.  
> **username_5**: PS: FWIW, wildcard types in Java are existential types, though rather limited and ad-hoc (which may be part of the reason why they are somewhat confusing).  
> **username_6**: Would it be possible to emulate the case of type dispatch feature of typeclasses as overloaded functions in OOP? That would not be the same of course, since the function def. would be independant of the class, whereas in the typeclass, the function is mandatory, but it appears to me as possible solution.  
> **username_5**: @didierc, that would be restricted to cases that can be fully resolved statically. Moreover, to match type classes it would require a form of overloading resolution that is able to distinguish based on the return type alone (see item 1).  
> **username_6**: Ah, right, classic overloading doesn't work on return type! Thanks, I overlooked that point. Very good answer btw.  

---

### Answer by username_1 on 2012-03-07. Score: 7

In addition to Andreas's excellent answer, please keep in mind that type classes are meant to streamline *overloading*, which affects the global name space. There is no overloading in Haskell other than what you can obtain via type classes. In contrast, when you use object interfaces, only those functions that are declared to take arguments of that interface will need to worry about the function names in that interface. So, interfaces provide local name spaces.

For example, you had `fmap` in an object interface called "Functor". It would be perfectly ok to have another `fmap` in another interface, say "Structor". Each object (or class) can pick and choose which interface it wants to implement. In contrast, in Haskell, you can have only one `fmap` within a particular context. You cannot import both Functor and Structor type classes into the same context.

Object interfaces are more similar to Standard ML signatures than to type classes.

> **Comments:**
> **username_2**: and yet there seems to be a close relationship between ML modules and Haskell type classes. http://www.cse.unsw.edu.au/~chak/papers/DHC07.html  

---

### Answer by username_3 on 2013-11-08. Score: 1

In your concrete example (with Functor type class), Haskell and Java implementations behave differently. Imagine you have Maybe data type and want it to be Functor (it is really popular data type in Haskell, which you can easily implement in Java as well). In your Java example you will make Maybe class implement your Functor interface. So you can write the following (just pseudo code because I have c# background only) :
Maybe val = new Maybe(5);
Functor res = val.fmap(someFunctionHere);

Notice that the res has type Functor, not Maybe. So this makes Java implementation almost unusable because you lose concrete type information, and need to do casts. (at least I failed to write such an implementation where types were still present).
With Haskell type classes you will get Maybe Int as a result.

> **Comments:**
> **username_4**: I think this issue is due to Java not supporting higher kinded types, and is not related to the interfaces Vs typeclasses discussion. If Java had higher kinds, then fmap could very well return a `Maybe<Int>`.  

---

