tags:

views:

104

answers:

2

I have a few procedures that, for simplicity's sake, look like the following:

public String fetchValueAsString(String key);
public DateTime fetchValueAsDateTime(String key);

I want something like

public <X is a String or a DateTime> X fetchValue(String key);  // pseudo-code

that I could call like this (without casting; the type is implied by the passed parameters):

String str = fetchValue("subject");
DateTime dt = fetchValue("startDate");

I know I could just have one method that returns the Object type and just do a casting conversion, but I'm wondering if there is a way I can have just one method called, and somehow use generics to determine the return value. So, is it possible in Java (it is in C#)?

A: 

Because of type erasure, in Java the return type would have to be passed in explicitly:

public <X> X fetchValue(Class<X> type, String key);

If you know the value is going to be of the correct type no matter what, you don't have to pass in the Class<X>, and you can simply do a cast to (X) in the implementation. However, you'll get a compiler warning. With the Class<X> passed in you can do type.cast(value) safely, and more importantly make an attempt at converting it to the correct type if is not already of that type.

Kirk Woll
Only if the type isn't implicit in the key
Jherico
Isn't the key a string?
Kirk Woll
Its a string that presumably encodes some information, which may just be data, but may include a type. Consider "date:2010-03-01" vs "2010-03-01"
Jherico
type erasure has nothing to do with it: when "fetchValue(key)" is invoked there's just no way of knowing what result type user wants.
Nikita Rybak
Type erasure has everything to do with it if you look at the C# example. (The generic argument is explicitly passed and used to perform a general conversion from the source type to the target type.)
Kirk Woll
@Kirk Where's that example? Will C# guess what return value I want calling method _doIt(someData)_?
Nikita Rybak
@Jherico, why would the keys look like that? Your example looks like data/values. A key would (presumably) be something like "address" and "firstName".
Kirk Woll
@Nikita, it's in the OP's question: http://stackoverflow.com/questions/392931/one-function-with-varying-return-types-possible-with-generics. And in C#, generic type inference never operates on the return type, so the invocation would look like (in Java): <Integer> parseString("myKey"). In C#: ParseString<int>("myKey"). (Of course the Java example would not actually work -- because of type erasure.)
Kirk Woll
@Kirk Sorry, I see your point now. (Although, the difference in two ways of passing types seems pretty minor to me.)
Nikita Rybak
+2  A: 

Sure, but it will only work if the datatype is implied by the passed parameter.

I can declare the following and get no error:

public static <T> T parseString(String s) {
    return (T) new Date();
}

public static void test() {
    Date dt = parseString("date");
}

But the upshot to this kind of thing is the interior of your parsing function is going to have to be able to look at the string and determine the target type and its going to have to do a lot of casting inside its body to work properly.

Your question leaves somewhat ambiguous whether this is the kind of thing you want, or if what you really want is to have the type of the receiver determine either the method called or the behavior inside the method. This is, AFAIK not possible. Once you're in the method, all you have to work with is the string.

Jherico
But it is of course "unsafe".
Tom Hawtin - tackline
He didn't ask if it was safe.
Jherico
I didn't ask if it was safe.
Generics