On Mon, Oct 13, 2008 at 4:08 PM, Ryan Ingram <ryani.spam@gmail.com> wrote:
On Mon, Oct 13, 2008 at 11:18 AM, Arun Suresh <arun.suresh@gmail.com> wrote:
] you seem to have read my mind [:)].. i actaually hit upon this issue while
] trying to "transcode" some C++ to Haskell..

(literate haskell post, save it into "draw.lhs" and you can load it in ghci!)

What you usually want when you have some "closed world" OO class
hierarchy is to replace the hierarchy with an ADT.

For example:

class Drawable {
   virtual void render() = 0;
}

class Rectangle : public Drawable
{
   Rectangle(Point corner1, Point corner2);
   ...
}

class Circle : public Drawable
{
   Circle(Point center, float radius);
   ...
}

turns into

> data Point = Pt { x :: Float, y :: Float } deriving Show
> data Drawable = Rectangle Point Point | Circle Point Float

I agree that this does look more succinct... but what if I write some generic code for the
in the render method of the Drawable class and package it into a library..

Now my client want to write another subclass for Drawable...
He can do that in any other file... package.. whatever...

How would he do that in Haskell ???
considering he may not modify the source file in while i have defined the Drawable ADT..

I know it is possible using Type Classes... Have a Drawable Type Class.. etc.. etc..
Is there probably a better way of dooing it ??



> render :: Drawable -> IO ()
> render (Rectangle p1 p2) = putStrLn (concat ["Rectangle from ", show p1, " to ", show p2, "."])
> render (Circle center radius) = putStrLn (concat ["Circle at ", show center, " with radius ", show radius, "."])

This inverts the control from the OO structure; in the OO the
interface is centralized and the data is spread throughout the source.
 In the pattern-matching style, the data is centralized (in the ADT)
but the interface can be spread out.

For example, to add a new function "area()" to Drawable, in the OO
style you have to add it to Drawable and put an implementation into
every class that descends from Drawable, modifying all those modules.
But in Haskell you could declare a new function in one place:

> area :: Drawable -> Float
> area (Rectangle p1 p2) = abs (x p2 - x p1) * abs (y p2 - y p1)
> area (Circle _ r) = pi * r * r

On the other hand, adding new data to Rectangle or Circle requires
changing all the pattern matches spread throughout the source, which
is somewhat annoying.  So there are benefits of both styles.

It's possible to emulate the OO style in Haskell, using existential
types, but it is a lot harder.  It's easier to stick with what the
language is good at! :)

Hmmm... I suspect this answers the question I stated above...


 -- ryan

-Arun