[Haskell-cafe] [Newbie] Quest for inheritance
ralfla at microsoft.com
Mon Jun 6 21:10:25 EDT 2005
Thanks for your investigation.
Regarding your guess, the code does *not* use "state monads (for
mutable data)". The whole example would make sense without IO.
(So this approach is *all* different from OOHaskell :-))
The IO monad is used in Poormens2 because some of the
methods might want to do side effects.
For instance, in the Shape example, we want to see
the progress of drawing at the Console. Also, we added
an extra feature to "observe" the invocation of setters.
The operators (.?.) and (.!.) can be thought of as generic
getters and setters. In fact, close inspection reveals
that they rather model reading and writing (or call it
object observation and object mutation).
Mutability is achieved in Poormens2 merely by having setters.
(Optionally, if you like, you *could* use the IO monad to carry around
objects. Remember, in OOHaskell, the IO monad provides IORefs for
mutable objects; something not used in Poormens2.)
If you remove the IO monad, then the Poormens2 style is really a
variation on the style hinted at in Gracjan's email.
One interesting difference worth noting is that Gracjan places
the actual getters in classes while Poormens2 just uses overloaded
functions defined in terms of the generic operators (.!.) and (.?.).
But I assert that this is a detail or a minor variation point.
There could be monadic and non-monadic versions in the Subtype class;
I was just too lazy at that time -- assuming that one needs monads in
almost all cases anyhow. (After all, we are trying to understand
the migration of imperative OO code to Haskell.)
You might say that the fact whether the methods (and getters and
setters, say properties) are monadic or not should not disturb the
general framework, whereas it does seem to affect the design of the
Subtype class used in Poormens2. In particular, you might say that
the result type of a getter could be just *any* type: why then
expose the monadic status in the framework's types?
This is needed for the generic operator (.!.).
This operator captures an *in-place* update. That is, it applies
the mutator to the supertype component of the datum at hand. Since the
aspect of selecting that component *and* putting back the updated
component is captured generically, the operator takes
a type-preserving function on the supertype and lifts it to
a type-preserving function on the subtype. So type preservation
is in the type of the generic mutator, and we need the monadic
variation on type preservation (i.e., a -> IO a) -- if we anticipate that
any mutator will have side effects (in addition to those related to
the mutation of the object at hand, which is just explicit in the
type!!) It is then just a consistent style to provide
a similarly monadic type for generic observers.
We call this a poor mens' approach because the coding style does not
allow for a direct translation of C++/C#/Java OO code -- something
we aim to provide by OOHaskell (within limits of course).
> -----Original Message-----
> From: Cédric Paternotte [mailto:cpaternotte at gmail.com]
> Sent: Monday, June 06, 2005 3:36 PM
> To: Ralf Lammel
> Cc: haskell-cafe at haskell.org; Gracjan Polak
> Subject: Re: [Haskell-cafe] [Newbie] Quest for inheritance
> Hi Ralf,
> > I should have mentioned
> > http://homepages.cwi.nl/~ralf/OOHaskell/src/PoorMens2/
> > (again *not* using OOHaskell)
> It's been an interesting evening. I've been having a go at your
> poormen's source code and, although it's different from OOHaskell, I
> still find it very similar in the sense that it's using the same
> concepts, namely infix operators (for syntactic sugar I assume) and
> state monads (for mutable data). But I had a look at it anyway ;)
> From what I gathered today infix operators are just like ordinary
> functions, that differ only in the way you pass them parameters. I
> understand the .?. and .!. operators in your code are shortcuts that
> apply a function to the parent type, respectively for get and set
> The only thing I couldn't figure is the reason of using monads. I
> noticed they (returnIO) were extensively used in the setters and in
> the .!. operator. Do monads provide features without which this whole
> thing wouldn't be possible ? What is it exactly they provide in this
> context ?
> > A more general and preliminary observation:
> > the entire approach is potentially more about
> > object *composition* (and perhaps delegation)
> > rather than inheritance.
> That's also the way I see it.
More information about the Haskell-Cafe