Haskell V Java type checking

Below is a Haskell program with a sub-class.
It is followed my attempt to code the same concepts in Java.
Three questions:
1) Are the two examples close enough? (very subjective)
2) In this example, what are the advantages of the Haskell type checking over the Java type checking?
3) Are there more general advantages of Haskell type checking over Java type checking?

==== Haskell program===
data C = C deriving Show
data D = D deriving Show

class A t where
f::t -> t

instance A C where
f C = C

instance A D where
f D = D

class A t => B t where
g::t->t

instance B C where
g C = C

instance B D where
g D = D

-- The functions are only used for type, class and instance checking.
-- Check the type and class instances
:info f C
:info f D
:info f C
:info g C
-- output of last info command
class A t => B t where g :: t -> t -- Defined at t1.hs:14:2
data C = C -- Defined at t1.hs:1:6
instance Show C -- Defined at t1.hs:1:22-25
instance B C -- Defined at t1.hs:17:10-12
instance A C -- Defined at t1.hs:7:10-12

=====Java Program===
import java.lang.Class;

interface A {}
class A_INSTANCE implements A {}

interface B extends A{}
class B_INSTANCE implements B {}

class C {}
class D {}

public class DEMO1 {
public static void main(String args[]) {

// variables are used to check class
A_INSTANCE ac = new A_INSTANCE();
A_INSTANCE ad = new A_INSTANCE();
B_INSTANCE bc = new B_INSTANCE();
B_INSTANCE bd = new B_INSTANCE();

System.out.println("Object's Class name =>"+ ac.getClass().getName());
System.out.println("Object's Class name =>"+ ad.getClass().getName());
System.out.println("Object's Class name =>"+ bc.getClass().getName());
System.out.println("Object's Class name =>"+ bd.getClass().getName());

}
}
//Java output
Object's Class name =>A_INSTANCE
Object's Class name =>A_INSTANCE
Object's Class name =>B_INSTANCE
Object's Class name =>B_INSTANCE

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

covariance

Well you left methods out of the Java classes so the answer to Q1 is NO.

Where are f and g?

The short answer is:
1) No. I don't see anything in your Java code that corresponds to the operations f and g (as already noted) Nor do I see anything that connects the data types C and D to their associated instances of classes A and B.
2) Impossible to say, since the two pieces of code aren't obviously equivalent.
3) Once you start dealing with parameterized types, you may find that the Java encoding gets painful. Also, Haskell can automatically infer type-class instances in ways your Java code will have to do manually.

I'd recommend doing a search for encodings of Haskell type class in Scala, and working backwards from those to see what you can achieve in Java. This would be instructive in showing you where Java can or can't encode the desired semantics.

functions added

I added the functions
import java.lang.Class;

interface A {T f(T a);}
class A_INSTANCE implements A {public T f(T a) {return a;}}

interface B extends A{T g(T a);}
class B_INSTANCE implements B {public T g(T a) {return a;} public T f(T a) {return a;}}

class C {}
class D {}

public class DEMO1 {
public static void main(String args[]) {
C cc = new C();
D dd = new D();
A_INSTANCE ac = new A_INSTANCE();
A_INSTANCE ad = new A_INSTANCE();
B_INSTANCE bc = new B_INSTANCE();
B_INSTANCE bd = new B_INSTANCE();

System.out.println("Object's Class name =>"+ ac.getClass().getName());
System.out.println("Object's Class name =>"+ ad.getClass().getName());
System.out.println("Object's Class name =>"+ bc.getClass().getName());
System.out.println("Object's Class name =>"+ bd.getClass().getName());
System.out.println("f(cc) "+ ac.f(cc).getClass().getName());
System.out.println("f(ad) "+ ad.f(dd).getClass().getName());
System.out.println("f(bc) "+ bc.f(cc).getClass().getName());
System.out.println("f(bd) "+ bd.f(dd).getClass().getName());

}
}

/*
The Java out put is
Object's Class name =>A_INSTANCE
Object's Class name =>A_INSTANCE
Object's Class name =>B_INSTANCE
Object's Class name =>B_INSTANCE
f(cc) C
f(ad) D
f(bc) C
f(bd) D
*/

Nor do I see anything that connects the data types C and D to th

// The angled brackets were stripped out
import java.lang.Class;
interface A<T> {T f(T a);}
class A_INSTANCE<T> implements A<T> {public T f(T a) {return a;}}

interface B<T> extends A<T>{T g(T a);}
class B_INSTANCE<T> implements B<T> {public T g(T a) {return a;} public T f(T a) {return a;}}

class C {}
class D {}

public class DEMO1 {
public static void main(String args[]) {
C cc = new C();
D dd = new D();
A_INSTANCE<C> ac = new A_INSTANCE<C>();
A_INSTANCE<D> ad = new A_INSTANCE<D>();
B_INSTANCE<C> bc = new B_INSTANCE<C>();
B_INSTANCE<D> bd = new B_INSTANCE<D>();

System.out.println("Object's Class name = "+ ac.getClass().getName());
System.out.println("Object's Class name = "+ ad.getClass().getName());
System.out.println("Object's Class name = "+ bc.getClass().getName());
System.out.println("Object's Class name = "+ bd.getClass().getName());
System.out.println("f(cc) "+ ac.f(cc).getClass().getName());
System.out.println("f(ad) "+ ad.f(dd).getClass().getName());
System.out.println("f(bc) "+ bc.f(cc).getClass().getName());
System.out.println("f(bd) "+ bd.f(dd).getClass().getName());

}
}

/*
Object's Class name = A_INSTANCE
Object's Class name = A_INSTANCE
Object's Class name = B_INSTANCE
Object's Class name = B_INSTANCE
f(cc) C
f(ad) D
f(bc) C
f(bd) D
*/

Much closer

That is starting to look like a pretty straight-forward translation from type classes to Java interfaces. The biggest remaining catch I can see is that you are using the A_INSTANCE and B_INSTANCE classes to cheaply define both the C and D instances of the type classes, which is only possible because you've made the operations be trivially parametric. In a more realistic example you'd need to define one INSTANCE for each data type and type-class, just like your Haskell example.

Back to your questions:

Are the two examples close enough? (very subjective)

Close enough for me, but I'm not an expert. I'm not sure modelling type-class dependencies as interface inheritance is the right choice, but it doesn't seem to impact this example.

In this example, what are the advantages of the Haskell type checking over the Java type checking?

In this example? It is primarily that the Haskell code does not have to explicitly instantiate and pass around the instance "dictionaries" like bd. Note also that a Haskell implementation might do something more efficient than simple dictionary-passing, while your Java encodes that particular implementation.

Are there more general advantages of Haskell type checking over Java type checking?

Assuming you mean for the particular case of your type-class encoding? I'll again say that once you have to deal with parametric types and/or inferred type-class instances (e.g., Ord on pairs), you might find that your Java encoding forces you to manually write a lot of what the Haskell compiler infers.

If you mean are there advantages of Haskell over Java more generally, that seems like a difficult question to answer succinctly. Let's just say "yes," because they are languages designed with very different goals and constraints.

Well info

Are there more general advantages of Haskell type checking over Java type checking?

Well your use of info I think shows a major advantage.

Also along the same lines kind is an advantage:
*Main> :kind Maybe
Maybe :: * -> *
*Main> :kind Maybe Int
Maybe Int ::

More expressive

Are there more general advantages of Haskell type checking over Java type checking?

Brief answer: yes. Dispatch based on type classes is much more general than dispatch based on inheritance, because it is decoupled from concrete values. You can not just dispatch on the type of your (first) argument, but on the type of anything -- e.g. the result type of a function call. It also naturally generalizes to dispatch over multiple types.

Also, parametric polymorphism often is more expressive than subtyping, e.g. because it looses less information. For a trivial example, consider this function in Haskell:

h :: A a => a -> a
h x = f x

Then h C will have type C, while the "equivalent" Java is

A h(A x) { return x.f(); }

where h(new C) has type A, and you have to downcast to get back a C.

Edit: (On the other hand, you can also do some things with subtyping that require additional features in Haskell.)

Another advantage of type classes is the ability to define instances for a given class and type after the fact, i.e. you don't need to anticipate the class when you define the type. This retroactive adaption is not possible in Java, where you would need to modify the implements relation of the class itself.