Tuesday, May 8, 2012

C# said, Java said. Constraining generic's type

C# version:

public class InterfaceDemo {
    public static void Main(string[] args) { 
        
        Geek john = new Geek("John");
        Geek paul = new Geek("Paul");

        Hipster george = new Hipster("George");
        Hipster ringo = new Hipster("Ringo");

        var geekPersonalitiesIntroducer = new PersonalitiesIntroducer<Geek>();  
        var hipsterPersonalitiesIntroducer = new PersonalitiesIntroducer<Hipster>();

        geekPersonalitiesIntroducer.Introduce(paul,john);
        hipsterPersonalitiesIntroducer.Introduce(ringo,george);

        // won't work, you can only introduce geeks to each other.
        // error can be caught during compile-time:
        // geekPersonalitiesIntroducer.Introduce(paul,george);

        // won't work, you can only introduce hipsters to each other.
        // error can be caught during compile-time:
        // hipsterPersonalitiesIntroducer.Introduce(ringo,john);

    } 
}


interface IGreetable<T> {
    string Hello(T another);
}


class Geek : IGreetable<Geek> {

    string _name;
    public Geek(string name) {
        _name = name;
    }


    public string Hello(Geek another) {
        return "Howdy, " + another + ". I'm " + _name;
    }   


    override public string ToString() {
        return _name;
    }
}


class Hipster : IGreetable<Hipster> {
    
    string _name;
    public Hipster(string name) {
        _name = name;       
    }

    
    public string Hello(Hipster another) {
        return "Hola, " + another + ". I'm " + _name;
    }   


    override public string ToString() {
        return _name;
    }   
}


class PersonalitiesIntroducer<T> where T : IGreetable<T> {

    public void Introduce(T thisPerson, T toThatPerson) {
        
        System.Console.WriteLine(thisPerson + " meet " + toThatPerson);
        System.Console.WriteLine(thisPerson.Hello(toThatPerson));
        System.Console.WriteLine();
    }
}


Java version:

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

        Geek john = new Geek("John");
        Geek paul = new Geek("Paul");

        Hipster george = new Hipster("George");
        Hipster ringo = new Hipster("Ringo");

        PersonalitiesIntroducer<Geek> geekPersonalitiesIntroducer = new PersonalitiesIntroducer<Geek>();
        PersonalitiesIntroducer<Hipster> hipsterPersonalitiesIntroducer = new PersonalitiesIntroducer<Hipster>();

        geekPersonalitiesIntroducer.introduce(paul,john);
        hipsterPersonalitiesIntroducer.introduce(ringo,george);

        // won't work, you can only introduce geeks to each other.
        // error can be caught during compile-time:
        // geekPersonalitiesIntroducer.introduce(paul,george);

        // won't work, you can only introduce hipsters to each other.
        // error can be caught during compile-time:
        // hipsterPersonalitiesIntroducer.introduce(ringo,paul);

    }
}


interface Greetable<T> {
    String hello(T another);
}


class Geek implements Greetable<Geek> {

    String _name;
    public Geek(String name) {
        _name = name;
    }


    public String hello(Geek another) {
        return "Howdy, " + another + ". I'm " + _name;
    }


    @Override public String toString() {
        return _name;
    }
}


class Hipster implements Greetable<Hipster> {

    String _name;
    public Hipster(String name) {
        _name = name;
    }


    public String hello(Hipster another) {
        return "Hola, " + another + ". I'm " + _name;
    }


    @Override public String toString() {
        return _name;
    }
}


class PersonalitiesIntroducer<T extends Greetable<T>> {

    public void introduce(T fromPerson, T toAnotherPerson) {

        System.out.println(fromPerson + " meet " + toAnotherPerson);
        System.out.println(fromPerson.hello(toAnotherPerson));
        System.out.println();
    }
}

Output:

Paul meet John
Howdy, John. I'm Paul

Ringo meet George
Hola, George. I'm Ringo

The only part where Java and C# significantly differs(if at all) in these codes are in constraining the generic's type.

Contrast C#'s code:

class PersonalitiesIntroducer<T> where T : IGreetable<T> {

    public void Introduce(T thisPerson, T toThatPerson) {
  
        System.Console.WriteLine(thisPerson + " meet " + toThatPerson);
        System.Console.WriteLine(thisPerson.Hello(toThatPerson));
        System.Console.WriteLine();
    }
}

To Java's code:

class PersonalitiesIntroducer<T extends Greetable<T>> {

    public void introduce(T fromPerson, T toAnotherPerson) {

        System.out.println(fromPerson + " meet " + toAnotherPerson);
        System.out.println(fromPerson.hello(toAnotherPerson));
        System.out.println();
     }
}


C#'s syntax for constraining the generic type has more affinity with how the generics-using class will be used(instantiated). So you say in C# (and Java too):

PersonalitiesIntroducer<Geek> pi = new PersonalitiesIntroducer<Geek>(); // same syntax on both Java and C
// In C#, you can shorten it to:
var pi = new PersonalitiesIntroducer<Geek>(); 
// In Java 7, you can shorten it to:
PersonalitiesIntroducer<Geek> pi = new PersonalitiesIntroducer<>();

Though in Java, the class declaration is like this:
class PersonalitiesIntroducer<T extends Greetable<T>> 

You will not say in Java:
PersonalitiesIntroducer<Geek extends Greetable<Geek>> pi = new PersonalitiesIntroducer<Geek extends Greetable<Geek>>();

In Java, you instantiate generics the same way as C#.

Minor syntactic differences aside, C# and Java are very similar. You could even replace the Java code in movie Independence Day with C# and people won't even notice it

No comments:

Post a Comment