Fergus Henderson wrote:
> On 27-Aug-1999, Michael Hobbs <[EMAIL PROTECTED]> wrote:
> > Those who are into the more esoteric aspects of OO know that an object
> > has both a "type" (interface) and a "class" (implementation).
>
> Yes, but of course Haskell uses those two words in the opposite sense!
> In Haskell, a class specifies the interface while a type specifies the
> implementation. This is an unfortunate clash of terminologies.
Quite. Unfortunately, names convey a lot of implicit semantic meaning,
even when they are explicitly defined to have a different meaning. I
spent quite a few neuro-cycles trying to reconcile the Haskell OO system
with the rest of the OOPLs, before I realized that the terms had been
flip-flopped.
> > The OO support that currently exists in Haskell only addresses an
> > object's interface, and not very conveniently either. The reason I write
> > "not very conveniently" is because there is kludgy support for interface
> > inheritance
>
> Could you elaborate here? What is kludgy about Haskell's support for
> interface inheritence?
Yes, I should have elaborated more. The kludgy bit isn't in the
conceptual realm, it's more in the pragmatic realm. For example if you
have, "class Ord a => Foo a where ...", then when you want to declare
"instance Foo Bar where ..." you also have to declare "instance Ord Bar
where ..." and "instance Eq Bar where ...". It could be a little more
programmer-friendly was all I meant by it.[1]
(Actually, there is a slight conceptual bug too. Typically, when you
declare "class Ord a => Foo a where ...", your intent usually isn't to
subclass the the Ord interface, per se. Usually, the intent is that you
need to use comparison operators somewhere in your implementation and
you just need to make sure that the type is orderable.)
> > and it is not possible to create a list of values that may
> > be of different [Haskell] type, but all implement the same interface.
>
> Existential types solve that problem.
Many people have said this, but I still haven't found an instance where
existential types are *needed*. For example, if you declare a data type:
> data Shape = Shape {extent::Point, rotate::Float->Shape}
you implicitly define the following two functions:
> extent :: Shape -> Point
> rotate :: Shape -> Float -> Shape
The first argument to these functions is essentially the standard 'this'
argument. You can 'construct' different Shape values by defining the
following class:
> class ShapeClass a where
> mkShape :: a -> Shape
Note that "instance" declarations for this class would have the
following form:
> instance ShapeClass Square where
> mkShape this = let
> extent' = upperRight this -- or whatever
> rotate' deg = squareRotate this deg -- or whatever
> in Shape extent' rotate'
The 'this' argument to the "extent" and "rotate" functions noted above
is indirectly pulled from the argument given to the "mkShape" function.
More details on how this convention is used will follow...
Can anyone provide an example scenario, taken from an OO-perspective,
that *must* be handled using existential types? I don't doubt that such
scenarios might exist, it's just that I have yet to encounter one.
- Michael Hobbs
[1] Perhaps by using a single "instance" code block to define all the
required functions.