Over a million developers have joined DZone.

A Cross-Language Generics Trick - Java, Scala and C#

· Java Zone

Learn more about how the Java language, tools and frameworks have been the foundation of countless enterprise systems, brought to you in partnership with Salesforce.

Given a Pair<T, U> type in Java, Scala or C#, such as Map.Entry, Tuple2 or KeyValuePair respectively, you can construct type-checked variadic heterogenous containers that you can write general methods to operate on.

Let's write a Pair interface for Java and C#:

interface Pair<T, U> {
 T _1();
 U _2(); }


Pair<String, Integer> pair = Pairs.pair("hello", 5);


val pair=("hello", 5)


val pair = Pairs.Pair("hello", 5);

I expect that's fine with most people. For C# you'd probably change 'pair' to 'Pair' for the method name. Then, to start introducing the trick:


Pair<Double, Pair<String, Integer>> withDouble = Pairs.pair(3.0, pair);


val withDouble = (3.0, pair)


var withDouble = Pairs.Pair(3.0, pair);

You can see that the type in the Java code starts to look a little messy; this is no accident. Explicit static typing makes us more likely to choose less expressive types. Anyway, we can add a method 'prepend' to the Pair type, which doesn't modify anything, but returns a new Pair consisting of a data item on the left and the original Pair on the right. So we get:


Pair<Double, Pair<String, Integer>> pair = Pairs.pair("hello", 5).prepend(3.0);


val pair = Pairs.pair("hello", 5) prepend 3.0


var pair = Pairs.Pair("hello", 5).Prepend(3.0);

So prepend must be an interesting method, because it looks like you can use it to add more type parameters to something. Clearly you can't, I'm just chaining Pairs, but it makes a nice effect. So far not very useful; I'll get to that. First let's implement prepend:


public class Pair<T, U> 
{ ...
public <V> Pair<V, Pair<T, U>> prepend(V v)
{ return pair(v, this); } }


implicit def Tuple2WithPrepend[T, U](tuple: (T, U)) = 
new { def prepend[V](v: V) = (v, tuple) }


public class Pair<T, U> 
{ ...
public Pair<V, Pair<T, U>> Prepend<V>(V v)
{ return pair(v, this); }

The nice part about this way of building up Pairs is that you can write methods to handle them instead of writing one per Pair arity. Specifically, you could gather up parameters for an immutable class then instantiate it in one go. In fact, that's what I do in a prototype for a JDBC wrapper. To wet the tastebuds (sorry, only Java for this one):

List<QuestionInfo> questions=select(conn).asString("question").asString("correct").asString("wrong").as(question).from("questions").toList();

The idea is that the above runs the SQL query: select question, correct, wrong from questions and constructs a QuestionInfo for each result, putting the result into a list.

The surprising thing is probably that there's no reflection or casting going on at all. Each asString (well, after the first one really) builds up more in a chain of generic types, then the .as(question) deconstructs them again. question is actually an F<Pair<String, Pair<String, String>>, QuestionInfo>, which means it's a function that takes 3 Strings and returns a QuestionInfo, roughly.

The above code comes from a working test case I published here.

It turns out that someone else had this idea way way way before I did, and made something professional out of it, though only some of that appears to be statically type-checked.

I hope that what I've showed here proves useful to you, and if you are my team leader and I pointed you at this page, remember that you saw it on the Internet, it's real, so you have to let me write it in our project.

From http://rickyclarkson.blogspot.com

Discover how the Force.com Web Services Connector (WSC) is a code-generation tool and runtime library for use with Force.com Web services, brought to you in partnership with Salesforce.


The best of DZone straight to your inbox.

Please provide a valid email address.

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}