[Haskell-cafe] Re: Modelling Java Interfaces with Existential data types

Ralf Laemmel Ralf.Laemmel at cwi.nl
Tue Jun 8 09:01:44 EDT 2004


Hi Mike,

Let's redirect to Haskell cafe.
http://www.mail-archive.com/glasgow-haskell-users%40haskell.org/msg06288.html
http://www.mail-archive.com/glasgow-haskell-users%40haskell.org/msg06289.html

thanks for your time to look into the HList paper.

>1. It looks like your HList is basically a "sugarized" version of
>
>data AnyMyInterface = Impl1 MyImplementation1 | Impl2 MyImplementation2
>
>with the same drawback: you require me to explicitly list all the possible
>implementations of my interface

I don't think that anything was required to be explicit:

If you mean this here:

type MyList =  MyImplementation1
           :*: MyImplementation2
           :*: HNil

... then note that this type is inferred!

So with HLists, there is nothing like your Impl1 and Impl2,
and no new datatype like your AnyMyInterface.

Just for clarity:

(i) I like comparing Haskell datatypes with Java classes.
(ii) In Haskell, when you want to say that you have different
implementations for the same interface, or when you want to say
that different datatypes provide implementations of a certain
interface, then you use Haskell's type class system. (iii) When
you define an interface in Java, you rather define a type class
in Haskell. Type class are of course more powerful, but we don't
mind. (iv) When you say "implements" in Java, you rather say
"instance" in Haskell. (v) When you define the methods of the
interface to be implemented in Java, you define the methods of
the instance. I would claim the Haskell code ends up being more
modular :-)

You immediately get a simple form of Java-like interface
polymorphism in Haskell, say when you got a constraint, then
you are polymorphic over implementations (instances) of that
constraint.

The crux of your concern seems to be that you want to package values
of different types (Java: classes). Indeed you want to have
heterogeneous containers modulo subtyping. And our lovely HLists are
just good for that, but they come with the added value that they
don't make the elements opaque as it is the case with the sometimes
troublesome existentials.

> It
>might be possible to load them via hs-plugins or to obtain using something
>similar to Clean Dynamics (btw, is there anything similar available for
>Haskell?).

Data.Dynamics
Not needed here.

>2. There will also be problems in gluing the utility/legacy code. E. g. if I
>want to call any list function on HLists (e.g. reverse). The idea of having
>heterogeneous FiniteMap can be implemented by storing the single-element
>lists, but it will complicate the code, which will work with the map.

I concur. Using HList for everything is perhaps too invasive.
The HList paper makes clear that there are certain cases where
HLists are really needed, and they are complementary what generics
provide you with in Java. I was just able to use them for something
were a Generic Java programmer uses Generics and subtyping for.

So existentials are perhaps Ok.
However, directly comparing the opaque values is untypeable,

>I'm completely confident with applying (==) to different type. It's quite a
>common operation in OO-world.

Yes, what you need is type-safe cast.
See paper 1 here:
http://www.cs.vu.nl/boilerplate/

>I would like to have the following behaviour:
>
>instance Eq AnyMyInterface where
>	(==) (AnyMyInterface a1) (AnyMyInterface a2) = 
>		if (typeOf a1) == (typeOf a2) then false else a1 == a2
>

Java is just a weakly typed subset of Haskell :-)

Here we go ...

-- Yet another heterogeneous equality
yaHEq :: (Typeable a, Typeable b, Eq a)  => a -> b -> Bool
yaHEq a b = case cast b of
             Just a' -> a == a'
             Nothing -> False

*Main> yaHEq True True
True
*Main> yaHEq True "True"
False
*Main>

As you said yesterday that the equality issue is your main problem,
let's wipe this out for existentials as well.

I revise your existential wrapper type to include all goodies that are
needed, say Eq and Typeable:

data AnyMyInterface = forall a. ( Eq a
                                , Typeable a
                                , MyInterface a
                                ) => AnyMyInterface a

This is just your list type:

type MyList' = [AnyMyInterface]

Here are two lists:

list4 = [ AnyMyInterface $ MyImplementation1 10
        , AnyMyInterface $ MyImplementation1 10
        ]
list5 = [ AnyMyInterface $ MyImplementation1 10
        , AnyMyInterface $ MyImplementation2 10
        ]

Here is a demo:

*Main> list4!!0 == list4!!1
True
*Main> list5!!0 == list5!!1
False


Cheers,
Ralf

PS1:
All code is here:
http://homepages.cwi.nl/~ralf/HList/code.html

PS2:
I guess Sheard's work on parameterised modules might also interest you.
http://portal.acm.org/citation.cfm?id=507648&dl=ACM&coll=portal
And John Huges Restricted Data types
as it shows how to reify dictionaries:




More information about the Haskell-Cafe mailing list