Monday, November 28, 2011

Comparing Type Classes with Other Languages

Difference between Typeclasses and Java Interfaces
  • 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.
  • A type class allows you to define a 'default' implementation for any of the defined operations. Interfaces are strictly type specifications only, no implementation.
  • Type classes were created as a structured way to express "ad-hoc polymorphism" [non-OO], 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, 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.
  • 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.
  • Methods are bound to an object, Haskell typeclasses are not.
  • Type classes were originally developed to deal with ad-hoc polymorphism
    such as operator overloading in a less ad-hoc manner
  • A type class defines a signature for a family of functions
    that every member of the type class must implement
  • Eq is parameterized in a single type, a
  • A type becomes a member of a type class by an instance declaration that implements
    the functions declared in the type class
  • data Nat = Zero | Succ Nat
    • The type Nat becomes a member of the type class Eq as follows:
      instance Eq Nat where −− Structural equality
      Zero == Zero = True
      Zero == (Succ ) = False
      (Succ ) == Zero = False
      (Succ x) == (Succ y) = x == y

data Point = FloatPoint Float Float
           | IntPoint Int Int
Haskell provides a very easy way to build/analyze them:
coord :: Point -> (Float, Float)
coord (FloatPoint x y) = (x,y)
coord (IntPoint x y) = (realToFrac x, realToFrac y)
 
main = do print (coord (FloatPoint 1 2))
          print (coord (IntPoint 1 2))
So ADTs in general are preferred in Haskell over the class-based solution of the same problem:
class Point a where
    coord :: a -> (Float, Float)
 
data FloatPoint = FloatPoint Float Float
instance Point FloatPoint where
    coord (FloatPoint x y) = (x,y)
 
data IntPoint = IntPoint Int Int
instance Point IntPoint where
    coord (IntPoint x y) = (realToFrac x, realToFrac y)



Comparison to Other Languages.

The classes used by Haskell are similar to those used in other object-oriented languages such as C++ and Java. However, there are some significant differences:
  • Haskell separates the definition of a type from the definition of the methods associated with that type. A class in C++ or Java usually defines both a data structure (the member variables) and the functions associated with the structure (the methods). In Haskell, these definitions are separated.
  • The class methods defined by a Haskell class correspond to virtual functions in a C++ class. Each instance of a class provides its own definition for each method; class defaults correspond to default definitions for a virtual function in the base class.
  • Haskell classes are roughly similar to a Java interface. Like an interface declaration, a Haskell class declaration defines a protocol for using an object rather than defining an object itself.
  • Haskell does not support the C++ overloading style in which functions with different types share a common name.
  • The type of a Haskell object cannot be implicitly coerced; there is no universal base class such as Object which values can be projected into or out of.
  • C++ and Java attach identifying information (such as a VTable) to the runtime representation of an object. In Haskell, such information is attached logically instead of physically to values, through the type system.
  • There is no access control (such as public or private class constituents) built into the Haskell class system. Instead, the module system must be used to hide or reveal components of a class.


Compared with Scala's Implicit Defs
http://blog.tmorris.net/the-power-of-type-classes-with-scala-implicit-defs/

No comments:

Post a Comment