Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

There are LOTS of things you can do with type classes, and they are super sexy. Let me try to enumerate them.

One commenter already noted higher-kinded type classes, which is the basis of Haskell's libraries and do-notation for monads. That's HUGE.

But besides higher-kinded type classes, there are others:

* Factories and constants in your interfaces. Type classes allow you to put a type variable in the return argument of a method. This lets you put factories and constants in your type classes. For example, if you look at the monoid type class:

  class Monoid a where
    mappend: a -> a -> a
    mzero: a
And I can implement this

  instance Monoid String where
    mappend x y = AppendStrings x y
    mzero = ""

  instance Monoid Integer where
    mappend x y = x + y
    mzero = 0
So now I can write generic code where I can get the "zero constant" of a type without knowing what type that is. I could just have a genericMonoid : T where T is a type variable, and all I know about it is that it belongs to class Monoid (maybe it's an integer, maybe it's a string, maybe it's something else). I can now get the zero value of whatever that type is. In fact, my method doesn't have to be dispatched on the type of some input argument. I can dispatch on the return value. Something like

  multiplyByZero : [Monoid T] int -> T  
  multiplyByZero 0 = mzero
  multiplyByZero n = mplus mzero (multiplyByZero (n-1))
(Forgive my crappy Haskell pseudo syntax, I haven't written it in a while). Not that multiply by zero is useful.

* Operators of greater arity than 1. So I hinted at this above. With "method syntax" arity is always 1. I have one "this". I can operate on it. For all other arguments to my method, I cannot actually constrain them to have the same type as "this". At best, with OOP, my method belongs to some base class, and I can insist that the non-this arguments are of base class type, but I cannot constrain them to have "this" type. This is illustrated in the monoid example above, or in the Eq example I gave, where it can be guaranteed that the two operands to == are always of the same type. In Java, the equals method has to take one argument of type "Object", while the "this" argument has the class's type.

* Multiparameter type classes. (This is behind a flag in the Haskell compiler). You can do something like this:

  class Eating E F where
    eat ::  E -> F -> Meal

  # E is short for Eater
  # F is short for Food
so now I can type check to make sure that eaters eat the right type of food.

  instance Carnivore Meat where
    eat = # specialized implementation for eating meat

  instance Carnivore Vegetables where
    eat = # specialized implementation for eating vegetables

  instance Vegeterian Vegetables where
    eat = # specialized implementation for vegeterian food


I'm not sure if all your examples were meant to be things that Rust doesn't have, but Rust certainly has polymorphic return values. For example, see the `Default` trait: http://static.rust-lang.org/doc/master/std/default/trait.Def...

It's also used to generate random values: http://static.rust-lang.org/doc/master/rand/trait.Rng.html

More generally, Rust supports polymorphism anywhere. e.g., The `Eq` trait: http://static.rust-lang.org/doc/master/std/cmp/trait.Eq.html

AFAIK, >1-arity polymorphism in OOP languages is generally achieved with double dispatch. But it's not as nice (or as easy to understand IMO) as in ad hoc polymorphism.

Rust does not have HKT or multi-param traits though.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: