[Haskell-cafe] OO idioms redux

Ben Rudiak-Gould benrg at dark.darkweb.com
Tue Oct 12 18:20:11 EDT 2004


On Tue, 12 Oct 2004, John Goerzen wrote:

> One of the best features of OO programming is that of inheritance.  It
> can be used to slightly alter the behavior of objects without requiring
> modification to existing code or breaking compatibility with existing
> APIs.

I hesitate to express a contrary opinion since it'll sound as though I'm
defending Haskell's limitations, but that's actually not the case here --
this was true even before I learned Haskell.

In my own OOP code (mainly C++) I've rarely used implementation
inheritance, and when I have I've never felt entirely happy about the way
it turned out; it always seemed a bit fragile and hacky. When I want to
take advantage of polymorphism I usually use abstract interfaces, and when
I want to share code I usually use containment and delegation, which has
always struck me as more robust.

In any case, Haskell does support polymorphic abstract interfaces and
containment and delegation. In your ConfigParser example you would have an
interface (say IConfigParser) which would be represented as a type class,
and two implementations (ConfigParser and EnvConfigParser) which would be
represented as instances of the type class. E.g.

	class IConfigParser a where
	  newConfigParser :: IO a
	  readConfigFile :: a -> FilePath -> IO ()
	  getFoo :: a -> IO Foo
	  setFoo :: a -> Foo -> IO ()
	  ...

	data ConfigParser = ...

	instance IConfigParser ConfigParser where ...

	data EnvConfigParser = ECP ConfigParser

	instance IConfigParser EnvConfigParser where
	  newConfigParser = liftM ECP newConfigParser
	  readConfigFile (ECP cp) path =
	    readConfigFile cp path >> envSubst cp
	  getFoo (ECP cp) = getFoo cp
	  ...

I should say, though, that this is very unidiomatic code. Partly this is
because I don't quite understand the meaning of your ConfigParser class --
does it exist before a configuration file is read? What is the meaning of
having more than one instance? Parsing configuration files strikes me as
more verb than noun, and I'd be more inclined in this case to declare a
single ConfigData type, a single function to write it to a file, and two
functions to read it, one with environment substitution and one without.
So I suppose my advice is twofold:

	1. Try replacing implementation inheritance with containment and
	   delegation when you translate to Haskell.

	2. Try revisiting the original problem and thinking about how to
	   solve it in a Haskellish way, rather than solving it in another
	   language and then translating.

-- Ben



More information about the Haskell-Cafe mailing list