Method with two generic collections of same class - java

I would like to implement the following method, but I'm uncertain how to do this in Java generics.
This is what I would like to have:
public <C extends Collection> C<DomainDTO> transform(C<DomainModel> arg);
This is what compiles, but doesn't ensure A and B are of the same class that extends Collection:
public <A extends Collection<DomainDTO>, B extends Collection<DomainModel>> A transform(B arg);
Thanks for any ideas, or just confirmation that it's impossible.
EDIT:
I'll try to word this better, since it seems people confuse what I'm looking for. The use case here is (should be) simple. I need a method to populate a Collection of DTOs from a Collection of models. Right now I have many methods for different Collections, but I would prefer to have one generic method that takes any Collection as the parameter, and returns the DTOs in a Collection of the same class.

Specify the type of the collection parameter, not the collection itself:
public <T> Collection<T> transform(Collection<T> arg);
If the question is asking for both the element type and the collection type to be the same:
public <T, C extends Collection<T>> C transform(C arg);

EDIT: The question originally was ambiguous, to say the least. My proposed solution is not applicable to the edited question. However, the recommendation I made is still valid:
I wonder how you would like to implement this without using newInstance etc. You have to create a new instance of an unknown type...
You might alternatively consider a signature [...] where the caller can pass the target collection manually, and type safety is still maintained
EDIT: Updated code for the updated question:
The most generic form that I could imagine for this is sketched below.
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class SomeCollectionTest
{
static interface Converter<S, T>
{
T convert(S s);
}
static class Parser implements Converter<String, Integer>
{
#Override
public Integer convert(String s)
{
return Integer.parseInt(s);
}
}
public static void main(String[] args)
{
Collection<String> input = Arrays.asList("0","1","2","3");
List<String> listIn = new ArrayList<String>(input);
Set<String> setIn = new HashSet<String>(input);
Parser p = new Parser();
List<Integer> listOutA = convert(listIn, new ArrayList<Integer>(), p);
List<Integer> listOutB = convert(setIn, new ArrayList<Integer>(), p);
//List<Integer> noListOut = convert(listIn, new HashSet<Integer>(), p);
Set<Integer> setOutA = convert(setIn, new HashSet<Integer>(), p);
Set<Integer> setOutB = convert(setIn, new HashSet<Integer>(), p);
//Set<Integer> noSetOut = convert(listIn, new ArrayList<Integer>(), p);
System.out.println(listOutA);
System.out.println(setOutA);
}
private static <S, T, C extends Collection<? super T>> C convert(
Iterable<? extends S> input, C output, Converter<S, T> converter)
{
for (S s : input)
{
output.add(converter.convert(s));
}
return output;
}
}
And by the way: I'd even consider it as being advantageous to have the possibility to convert, for example, a Collection<DomainDTO> into a List<DomainModel> - particularly when you don't know the exact type of the first collection. Otherwise, you'd have to do this in two steps:
Collection<DTO> collectionOfDto = read();
Collection<DomainModel> dm = convert(dto); // Only receive a collection here...
// Sigh, I need a list. Maybe it already IS a list, but
// I don't know it. So I have to do this:
List<DomainModel> list = new ArrayList<DomainModel>(dm);

Related

Java generics challenge

Description
Firstly, all code to reproduce is shown below as well as with a UML diagram of the implementation. I understand that the naming I have gone for can be confusing, but I'm not able to come up with anything better for this minimal working example of my issue at hand.
The essence of the problem is in class AChildOne and is related to these three lines of code:
List<C<B>> cBList = new ArrayList<>();
List<C<BChild>> cBChildList = aChildTwo.get();
cBList.addAll(cBChildList); // <-- COMPILATION ERROR
If I change the first line in the above code snippet to:
List<C<? extends B>> cBList = new ArrayList<>();
the specific compilation error goes away, but it breaks other parts of the class.
If I remove the container class C from this implementation, things seem to work. However, in the actual implementation it does a bit more than what is shown in this minimal example so it is not so easy to remove it.
I was thinking that I would like to do something like this:
public class AChildOne implements A<? extends B>
but this is not allowed.
I suppose the problem is that I'm not able to successfully combine the generics for the return value of AChildOne::get() with the return value of AChildTwo::get().
I suspect that what I'm trying to do here is one of those 'gotchas' with generics, that you are not allowed to do.
Side note
Using Number, Integer and Double instead of my own classes, I'm essentially trying to do something like this:
public static void main(String[] args) {
List<C<Integer>> integerList = new ArrayList<>();
integerList.add(new C<>(1));
List<C<Double>> doubleList = new ArrayList<>();
doubleList.add(new C<>(3.14));
List<C<? extends Number>> numberList = new ArrayList<>();
numberList.addAll(integerList);
numberList.addAll(doubleList);
numberList.forEach(n -> System.out.println(n.value));
}
which does indeed work (C here is the same C as implemented below). However, when wrapping these things in separate classes, and using inheritance, it does not seem like I'm able to propagate the generics properly. If ONLY I could do this:
public class AChildOne implements A<? extends B>
I think it would work.
UML diagram
Code
import java.util.List;
public interface A<T> {
List<C<T>> get();
}
import java.util.ArrayList;
import java.util.List;
public class AChildOne implements A<B> {
private final AChildTwo aChildTwo = new AChildTwo();
public List<C<B>> get() {
List<C<B>> cBList = new ArrayList<>();
List<C<BChild>> cBChildList = aChildTwo.get();
cBList.addAll(cBChildList); // <-- COMPILATION ERROR
return cBList;
}
}
import java.util.ArrayList;
import java.util.List;
public class AChildTwo implements A<BChild> {
List<C<BChild>> list = new ArrayList<>();
public List<C<BChild>> get() {
return list;
}
}
public class B {
}
public class BChild extends B {
}
public class C<T> {
T value;
public C(T value) {
this.value = value;
}
T get() {
return value;
}
}
AChildOne cannot implement A<B>, because it cannot supply a List<C<B>>. It supplies a List<C<BChild>> (the return type of aChildTwo.get()). A List<C<BChild>> is not a subtype of List<C<B>>. If it were, it would break type safety:
List<C<BChild>> a = ...;
List<C<B>> b = a; // suppose you could do this
C<B> c = b.get(0);
c.value = new AnotherChildOfB();
BChild bchild = a.get(0).get(); // this would get an AnotherChildOfB instance, but is declared to return a BChild.
As you have correctly identified, AChildOne.get could return a List<C<? extends B>>. You would need to change the interface method's signature to make this work, rather than changing the inheritance clause.
Alternatively, AChildOne could implement A<BChild>. I actually recommend you choose this solution, because returning a wildcard is likely a code smell.

Multiple Generic Types

So first of all, I will specify that my question is not referring to having multiple generics being applied to a class. I know you can do that simply with a comma.
My question is if there is a way to have multiple possible extensions for a generics. For example:
public class Foo<? extends String>{}
public class Bar<? extends StringBuilder>{}
//combined
public class FooBar<? extends String, StringBuilder>{}
//or perhaps
public class FooBar<? extends String || StringBuilder>{}
I know the FooBar class will not compile but I hope that is helpful in explaining my question and the specified intent. To lastly reiterate my question: is it possible for two classes to be extended in the generic clause or a way that would simulate such an action indirectly?
Note I am not asking how generics work, nor how extensions work, nor anything involving how and when to use of generics, for I already know this. If the question needs clarification, I will edit to provide further understanding to the best of my abilities.
It's not possible for a class to extend both String and StringBuilder since classes only have one parent class. However, they can implement multiple interfaces, which you can specify with &.
class FooBar<T extends String & Runnable & Collection<Integer>> {}
(Note that String is final so it's not actually possible to satisfy the above constraint.)
So what you are asking isn't possible out of the box as John has said, but you can still achieve similar behavior using so called Either type which is used to represent situation where you can either 1 of 2 types.
You can easily find fully implemented Either class with simple google search, for example this one on github
For code snippet bellow lets consider this simplified version:
public class Either<L, R> {
private final L left;
private final R right;
private final boolean isRight;
private Either(L left, R right, boolean isRight) {
this.left = left;
this.right = right;
this.isRight = isRight;
}
public static <L, R> Either<L, R> left(L left){
return new Either<>(left, null, false);
}
public static <L, R> Either<L, R> right(R right){
return new Either<>(null, right, true);
}
public <T> T fold(Function<L,T> foldLeft, Function<R, T> foldRight){
return isRight ? foldRight.apply(right) : foldLeft.apply(left);
}
}
Now lets say you have interface with some method that should accept String or StringBuilder:
public interface IFooBar <T extends Either<? extends String, ? extends StringBuilder>>{
String doSomething(T t);
}
And implementation:
class FooBar implements IFooBar<Either<String, StringBuilder>> {
#Override
public String doSomething(Either<String, StringBuilder> either) {
return either.fold(s -> "String: " + s, sb -> "StringBuilder:" + sb);
}
}
Then you can simply use it like this:
public static void main(String[] args) {
IFooBar<Either<String, StringBuilder>> fooBar = new FooBar();
// Since in this case it is single method interface you can even use lambda expression
// IFooBar<Either<String, StringBuilder>> fooBar = either -> either.fold(s -> "String: " + s, sb -> "StringBuilder:" + sb);
System.out.println(fooBar.doSomething(Either.left("Foo")));
System.out.println(fooBar.doSomething(Either.right(new StringBuilder("Bar"))));
}
I hope that this helps you.

Safe workaround for broken contravariant bounds in Java?

As discussed in Bounding generics with 'super' keyword the Java type system is broken/incomplete when it comes to lower bounds on method generics. Since Optional is now part of the JDK, I'm starting to use it more and the problems that Guava encountered with their Optional are starting to become a pain for me. I came up with a decent work around, but I'm not sure its safe. First, let me setup the example:
public class A {}
public class B extends A {}
I would like to be able to declare a method like:
public class Cache {
private final Map<String, B> cache;
public <T super B> Optional<T> find(String s) {
return Optional<T>.ofNullable(cache.get(s));
}
}
So that both of the following work:
A a = cache.find("A").orElse(new A())
B b = cache.find("B").orElse(new B())
As a workaround, I have a static utility method as follows:
public static <S, T extends S> Optional<S> convertOptional(Optional<T> optional) {
return (Optional<S>)optional;
}
So my final question, is this as type-safe as the 'ideal' code above?
A a = OptionalUtil.<A,B>convertOptional(cache.find("A")).orElse(new A());
You're effectively trying to view the Optional<B> returned as an Optional<A> without changing the return type (since you can't use the super). I would just map the identity function.
A a = cache.find("A").map(Function.<A> identity()).orElse(new A());
// or shorter
A a = cache.find("A").<A> map(x -> x).orElse(new A());
I don't see anything wrong with your approach though.
Yes, your code is type safe because you are casting Optional<T> to Optional<S>, and T is always an S. You can indicate this to the compiler by using the #SuppressWarnings("unchecked") annotation on your convertOptional utility method.
As well as the other excellent answer, you could do it this way. Note the lack of generics compared to your first version.
package com.company;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
public class Cache {
private static final Function<A,A> CAST_TO_A = Function.<A>identity();
private final Map<String, B> cache = new HashMap<>();
public Optional<B> find(String s) {
return Optional.ofNullable(cache.get(s));
}
public static void main(String[] args) {
Cache cache = new Cache();
Optional<B> potentialA = cache.find("A");
A a = potentialA.isPresent() ? potentialA.get() : new A();
A anotherWay = cache.find("A").map(CAST_TO_A).orElse(new A());
B b = cache.find("B").orElse(new B());
}
public static class A {}
public static class B extends A {}
}
In practice, I think it is type-safe, because the Optional class is immutable and T is subtype of S.
Beware though that T is subtype of S does NOT mean that Optional<T> is subtype of Optional<S>, so theoretically that cast is not correct. And in some cases, it is not safe to do such kind of casts and it can be problematic at run-time (as it happens with List).
So my suggestion is to avoid casts whenever we can, and I would rather define a method like the getOrElse. Also, for the sake of completeness, the generic types in your method convertOptional could be simplified as below.
class OptionalUtil {
public static <S> S getOrElse(Optional<? extends S> optional, Supplier<? extends S> other) {
return optional.map(Function.<S>identity()).orElseGet(other);
}
public static <S> Optional<S> convertOptional(Optional<? extends S> optional) {
return (Optional<S>)optional;
}
}
And they could be use like that:
A a1 = OptionalUtil.getOrElse(cache.find("A"), A::new);
A a2 = OptionalUtil.<A>convertOptional(cache.find("A")).orElseGet(A::new);
[EDIT] I replaced the method orElse by orElseGet, because with the former a new A object will be created even if the Optional is present.

In a Transformer, how to specify that the types fo the classes being transformed are of the same type?

I'm having a very simple yet confuse question at the same time.
In a Transformer, is there a way to specify that the types of the classes being transformed are the same type?
To make it clear, I'll share the code:
Transformer<Set<?>, List<?>> transformer = new SetToListTransformer();
Is there a way for me to specify that the Set and the List are of the same type?
Also when writing the transformer I did this, and I assume it serves no purpose:
private static class SetToListTransformer implements Transformer<Set<?>, List<?>> {
#Override
public List<?> transform(final Set<?> input) {
return this.doTransform(input);
}
public <T> List<T> doTransform(final Set<T> input) {
...
}
}
The thing is, I cannot type the SetToListTransformer since I do not really care about what types are inside, I just care that they are the same type.
Any help would be appreciated!
PS: I'm not really transforming a Set into a List, I'm using other types, I just used them to clarify the code :)
Try to bind both wildcards to the same type paramter, like this:
class SetToListTransformer<E> implements Transformer<Set<E>, List<E>> {
#Override
public List<E> transform(Set<E> from) {
...
}
}
Make your class generic:
private static class SetToListTransformer <T> implements Transformer<Set<T>, List<T>> {
#Override
public List<T> transform(Set<T> input) {
return this.doTransform(input);
}
public List<T> doTransform(Set<T> input) {
...
}
}
Note, however, that this implementation is quite strict with types. You wont be able to use a SetToListTransformer<Number> to convert from Set<Integer> to List<Number>, although Integer IS a Number.
There's no way to enforce the desired constraint on your transform implementation, since there is no way to impose any relationship between generic wildcards. Each of the two ? in your SetToListTransformer declaration are doomed to each mean some unknown type with no way to bound them to each other.
As others pointed out, the easiest solution is to make SetToListTransformer generic. For example:
class SetToListTransformer<T> implements Transformer<Set<? extends T>, List<T>> {
#Override
public List<T> transform(final Set<? extends T> input) {
final List<T> output = new ArrayList<T>(input.size());
output.addAll(input);
return output;
}
}
Of course this requires you to instantiate transformers with specific type arguments. This should be fine as long as SetToListTransformer is cheap. But, you indicated you just want to use one instance. Here's how to do that:
class MyTransformers {
// There is no reason to expose SetToListTransformer now.
// Keep it here as an anonymous class.
private static final Transformer<Set<?>, List<?>> FROM_SET_TO_LIST =
new Transformer<Set<?>, List<?>>() {
#Override
public List<?> transform(final Set<?> input) {
return doTransform(input);
}
private <T> List<T> doTransform(final Set<T> input) {
final List<T> output = new ArrayList<T>(input.size());
output.addAll(input);
return output;
}
};
private MyTransformers() { }
public static <T> Transformer<Set<? extends T>, List<T>> fromSetToList() {
#SuppressWarnings("unchecked")//this is okay for any T because the impl is stateless
final Transformer<Set<? extends T>, List<T>> withNarrowedTypes =
(Transformer<Set<? extends T>, List<T>>)(Transformer<?, ?>)FROM_SET_TO_LIST;
return withNarrowedTypes;
}
}
Here's a usage example:
Set<Integer> intSet = new HashSet<Integer>();
intSet.add(42);
intSet.add(1337);
List<Number> numList = MyTransformers.<Number>fromSetToList().transform(intSet);
You can't express that constraint with the Transformer interface. You may create a subtype that imposes additional constraints, and use the subtype where Transformer was used.
interface StricterTransformer extends Transformer<Set<?>, List<?>>
public <T> List<T> transform2(Set<T> input) ;
/** javadoc additional contract: must behave as transform2(input) */
public List<?> transform(Set<?> input);
// in java8 we can give a "default" impl for this interface method
// that simply calls transform2(), so subclasses don't have to impl
// the transform() method, which is just boiler plate code.

Java generics: How to encode a Functor interface in Java?

I want to define a Functor class in Java. This works:
//a Function
public interface F<A,R> {
public R apply(A a);
}
public interface Functor<A> {
public <B> Functor<B> fmap(F<A,B> f);
}
However the return value of fmap should be not Functor, but the appropriate subclass. Usually this can be encoded with the CRTP, but here I seem to hit a wall because of the additional parameter A. E.g. the following and similar encodings don't work ("type parameter FInst is not within its bounds"):
public interface Functor<A, FInst extends Functor<A,FInst>> {
public <B, I extends Functor<B,FInst>> I fmap(F<A,B> f);
}
[Clarification]
With "appropriate subclass" I mean the type of the class being called itself. E.g. Lists are functors, so I would like to write something like
public class ListFunctor<A> implements ??? {
final private List<A> list;
public ListFunctor(List<A> list) {
this.list = list;
}
#Override
<B> ListFunctor<B> fmap(F<A,B> f) {
List<B> result = new ArrayList<B>();
for(A a: list) result.add(f.apply(a));
return new ListFunctor<B>(result);
}
}
I'm aware that I could write this even with the first definition I gave (because covariant return types are allowed), but I want that the return type "ListFunctor" is enforced by the type system (so that I can't return a FooFunctor instead), which means that the Functor interface needs to return the "self-type" (at least it is called so in other languages).
[Result]
So it seems what I want is impossible. Here is a related blog-post: http://blog.tmorris.net/higher-order-polymorphism-for-pseudo-java/
[Aftermath]
I stumbled over this age-old question of mine, and realized that this was the starting point of the amazing journey with my library highJ, containing much more than a simple Functor. I would have never imagine that people would use this crazy stuff for anything serious, but it happened, and that makes me very happy.
public interface Functor<A, FInst extends Functor<A,FInst>> {
public <B, I extends Functor<B,FInst>> I fmap(F<A,B> f);
}
This code generates an error because when you define I, you define it to be a subclass of Functor<B,FInst>, but the FInst parameter must be a subclass of Functor<B,FInst> in this case, while it is defined above as being a subclass of Functor<A,FInst>. Since Functor<A,FInst> and Functor<B,FInst> aren't compatible, you get this error.
I haven't been able to solve this completely, but I could do at least a half of the job:
import java.util.ArrayList;
import java.util.List;
interface F<A,R> {
public R apply(A a);
}
interface Functor<A, FClass extends Functor<?, FClass>> {
public <B> FClass fmap(F<A,B> f);
}
public class ListFunctor<A> implements Functor<A, ListFunctor<?>> {
final private List<A> list;
public ListFunctor(List<A> list) {
this.list = list;
}
#Override
public <B> ListFunctor<B> fmap(F<A,B> f) {
List<B> result = new ArrayList<B>();
for(A a: list) result.add(f.apply(a));
return new ListFunctor<B>(result);
}
}
This works, and it properly limits the set of allowed return types to ListFunctor, but it doesn't limit it to subclasses of ListFunctor<B> only. You could declare it as returning ListFunctor<A> or any other ListFunctor, and it would still compile. But you can't declare it as returning a FooFunctor or any other Functor.
The main problem with solving the rest of the problem is that you can't limit FClass to subclasses of ListFunctor<B> only, as the B parameter is declared at the method level, not at the class level, so you can't write
public class ListFunctor<A> implements Functor<A, ListFunctor<B>> {
because B doesn't mean anything at that point. I couldn't get it working with the second parameter to the fmap() either, but even if I could, it would just force you to specify the return type twice - once in the type parameter and once more as the return type itself.
Looking from a different angle, it seems Functor shouldn't be modeled as a "Wrapper" around the data, but actually more like a type-class, which works on the data. This shift of perspective allows to encode everything without a single cast, and absolutely type-safe (but still with a lot of boilerplate):
public interface Functor<A, B, FromInstance, ToInstance> {
public ToInstance fmap(FromInstance instance, F<A,B> f);
}
public class ListFunctor<A,B> implements Functor<A, B, List<A>, List<B>> {
#Override
public List<B> fmap(List<A> instance, F<A, B> f) {
List<B> result = new ArrayList<B>();
for(A a: instance) result.add(f.apply(a));
return result;
}
}
List<String> stringList = Arrays.asList("one","two","three");
ListFunctor<String,Integer> functor = new ListFunctor<String,Integer>();
List<Integer> intList = functor.fmap(stringList, stringLengthF);
System.out.println(intList);
//--> [3, 3, 5]
It seems I was too focused on packing both FromInstance and ToInstance in one type parameter (e.g. List in ListFunctor), which isn't strictly necessary. However, it's a heavy burden to have now not only A but also B as type parameter, which may make this approach practically unusable.
[Research]
I found a way to make this version at least a little bit useful: This functor can be used to lift a function. E.g. if you have F<String, Integer>, you can construct a F<Foo<String>, Foo<Integer>> from it when you have a FooFunctor defined as shown above:
public interface F<A,B> {
public B apply(A a);
public <FromInstance, ToInstance> F<FromInstance, ToInstance> lift(
Functor<A,B,FromInstance, ToInstance> functor);
}
public abstract class AbstractF<A,B> implements F<A,B> {
#Override
public abstract B apply(A a);
#Override
public <FromInstance, ToInstance> F<FromInstance, ToInstance> lift(
final Functor<A, B, FromInstance, ToInstance> functor) {
return new AbstractF<FromInstance, ToInstance>() {
#Override
public ToInstance apply(FromInstance fromInstance) {
return functor.fmap(fromInstance, AbstractF.this);
}
};
}
}
public interface Functor<A, B, FromInstance, ToInstance> {
public ToInstance fmap(FromInstance instance, F<A,B> f);
}
public class ListFunctor<A, B> implements Functor<A, B, List<A>, List<B>> {
#Override
public List<B> fmap(List<A> instance, F<A, B> f) {
List<B> result = new ArrayList<B>();
for (A a : instance) {
result.add(f.apply(a));
}
return result;
}
}
//Usage:
F<String, Integer> strLenF = new AbstractF<String, Integer>() {
public Integer apply(String a) {
return a.length();
}
};
//Whoa, magick!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
F<List<String>,List<Integer>> liftedF = strLenF.lift(new ListFunctor<String, Integer>());
List<String> stringList = Arrays.asList("one", "two", "three");
List<Integer> intList = liftedF.apply(stringList);
System.out.println(intList);
//--> [3, 3, 5]
I think it's still not very useful, but at least way cooler than the other attempts :-P
Building on the answer of Sergey, I think I came close to what I wanted. Seems like I can combine his idea with my failed attempt:
public interface Functor<A, Instance extends Functor<?, Instance>> {
public <B, I extends Functor<B,Instance>> I fmap(F<A,B> f);
}
public class ListFunctor<A> implements Functor<A, ListFunctor<?>> {
final private List<A> list;
public ListFunctor(List<A> list) {
this.list = list;
}
#Override
public <B, I extends Functor<B, ListFunctor<?>>> I fmap(F<A,B> f) {
List<B> result = new ArrayList<B>();
for(A a: list) result.add(f.apply(a));
return (I) new ListFunctor<B>(result);
}
}
List<String> list = java.util.Arrays.asList("one","two","three");
ListFunctor<String> fs = new ListFunctor<String>(list);
ListFunctor<Integer> fi = fs.<Integer,ListFunctor<Integer>>fmap(stringLengthF);
//--> [3,3,5]
The remaining problem is that I could write e.g. ListFunctor<StringBuilder> fi = fs.<Integer,ListFunctor<StringBuilder>> without complaints from the compiler. At least I can look for a way to hide the ugly guts behind a static method, and to enforce that relation behind the scenes...
Does anyone still use Java and ponder this problem? You might find this useful...
I've been pondering this for a looooong time. I believe I've made something satisfactory. What I would really like to is indeeed impossible in Java.
This is ideal:
interface Functor<T, CONCRETE<A> extends Functor<A, CONCRETE>> {
CONCRETE<U> fmap(Func<T, U>);
}
Unfortunately, this is make-believe syntax. This kind of thing is possible in C++ with template-template parameters, but not Java.
I was tempted to write this simple thing:
interface Functor<T> {
Functor<U> fmap(Func<T, U>);
}
This works in some cases, because an implementation can return a covariant return type (for example, List could return a List from this function), but it breaks down when you try passing around generic variables of type "F extends Functor", or a subclass of Functor, etc...
What I ended up doing was introduce a "dummy type variable", like so:
interface Functor<CONCRETE, T> {
Functor<CONCRETE, U> fmap(Func<T, U>);
}
The "concrete type" should be the type itself, or some dummy type that guarantees the uniqueness of its implementors. Here's an example implementation:
public final class Array<T> implements Functor<Array<?>, T> {
private final T[] _values;
#SafeVarargs
public Array(T... values) {
_values = values;
}
#SuppressWarnings("unchecked")
#Override
public <A, RESULT extends Functor<Array<?>, A>> RESULT fmap(Function<T, A> f) {
A[] result = (A[]) new Object[_values.length];
for (int i = 0; i < _values.length; ++i) {
result[i] = f.apply(_values[i]);
}
return (RESULT) new Array<A>(result);
}
}
The cast to (RESULT) is safe because there can only be one type that matches "Functor, T>", and that's "Array". The disadvantage of this, is that generic code may need to pass around this "CONCRETE" type in a bunch of places, and it makes your signatures unwieldy. For instance:
public class Test {
public static <CONCRETE, FInt extends Functor<CONCRETE, Integer>, FBool extends Functor<CONCRETE, Boolean>> FBool intToBool(FInt ints) {
return ints.fmap(x -> x > 5);
}
public static void main() {
Array<Integer> ints = new Array<>();
Array<Boolean> bools1 = ints.fmap(x -> x > 5); // this works because Array<> implements fmap covariantly
Array<Boolean> bools2 = intToBool(ints); // but this also works thanks to our dummy CONCRETE type
}
}
I think you want to do something that makes no sense (type wise).
interface Getter<Type> {
Type get();
}
If your application wants a getter that returns Integers, don't give it one that returns Objects.
If you don't know if it will return Objects or Integers you are trying to do something the wrong way.
If YOU KNOW it will return Integers, then wrap the getter so that it casts to integers.
Hope this is what you are looking for .
EDIT:
Explanation of why (I think) this can not be done.
Objects have there types set when you use new.
Take each type and replace it with a letter.
Take any number of another objects and do the same.
What letter do you want your function to return?
If the answer is that you want a mix, well then its too late. Types are decided at new, and you are already past new.

Categories

Resources