[Haskell-cafe] Re: Functional version of this OO snippet

ajb at spamcop.net ajb at spamcop.net
Fri Dec 5 21:02:54 EST 2008

G'day all.

Thomas Davie wrote:

>> class IEngine a where
>>   foo :: a -> String
>>   bar :: a -> String -> String

"Apfelmus, Heinrich" <apfelmus at quantentunnel.de> replied:

> You don't even need a type class, a simple data type is enough.
>   data Engine = Engine { foo :: IO (), bar :: String -> IO () }

There is a tradeoff here, that you should be aware of.

1. Using typeclasses.

Pro: It works with the SPECIALIZE pragma.

Pro: You can put arbitrary data in the concrete data type which is
the instance of IEngine.  (If you don't, incidentally, this is called
a "traits typeclass".)

Con: You can't generate instances of IEngine dynamically at run-time
(at least without using unportable unsafeCast# magic).  So you're
limited to only those implementations that you (possibly dynamically)
link in.

2. Using records.

Pro: Usually simpler, and using fewer lines of code.

Pro: You can generate new "instances" at will, and you're not limited
to that which you link in.

Con: Usually more explicit arguments passed around.

Con: If your methods involve polymorphism, then the record will turn
out to have a higher-rank type, which isn't valid Haskell 98.

> This always works because all object methods expect a "self" argument.

That's not true for OO languages which have virtual constructors.

Haskell typeclasses support virtual constructors/factory methods just
fine, because the "self" type can appear anywhere in the signature,
including being the return value.  The monad "return" method is one
example of this.

Andrew Bromage

More information about the Haskell-Cafe mailing list