Multiple Generic Types - java

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.

Related

Can I define the Negatable interface in Java?

Asking this question to clarify my understanding of type classes and higher kinded types, I'm not looking for workarounds in Java.
In Haskell, I could write something like
class Negatable t where
negate :: t -> t
normalize :: (Negatable t) => t -> t
normalize x = negate (negate x)
Then assuming Bool has an instance of Negatable,
v :: Bool
v = normalize True
And everything works fine.
In Java, it does not seem possible to declare a proper Negatable interface. We could write:
interface Negatable {
Negatable negate();
}
Negatable normalize(Negatable a) {
a.negate().negate();
}
But then, unlike in Haskell, the following would not compile without a cast (assume MyBoolean implements Negatable):
MyBoolean val = normalize(new MyBoolean()); // does not compile; val is a Negatable, not a MyBoolean
Is there a way to refer to the implementing type in a Java interface, or is this a fundamental limitation of the Java type system? If it is a limitation, is it related to higher-kinded type support? I think not: it looks like this is another sort of limitation. If so, does it have a name?
Thanks, and please let me know if the question is unclear!
Actually, yes. Not directly, but you can do it. Simply include a generic parameter and then derive from the generic type.
public interface Negatable<T> {
T negate();
}
public static <T extends Negatable<T>> T normalize(T a) {
return a.negate().negate();
}
You would implement this interface like so
public static class MyBoolean implements Negatable<MyBoolean> {
public boolean a;
public MyBoolean(boolean a) {
this.a = a;
}
#Override
public MyBoolean negate() {
return new MyBoolean(!this.a);
}
}
In fact, the Java standard library uses this exact trick to implement Comparable.
public interface Comparable<T> {
int compareTo(T o);
}
In general, no.
You can use tricks (as suggested in the other answers) that will make this work, but they do not provide all of the same guarantees that the Haskell typeclass does. Specifically, in Haskell, I could define a function like this:
doublyNegate :: Negatable t => t -> t
doublyNegate v = negate (negate v)
It is now known that the argument and return value of doublyNegate are both t. But the Java equivalent:
public <T extends Negatable<T>> T doublyNegate (Negatable<T> v)
{
return v.negate().negate();
}
doesn't, because Negatable<T> could be implemented by another type:
public class X implements Negatable<SomeNegatableClass> {
public SomeNegatableClass negate () { return new SomeNegatableClass(); }
public static void main (String[] args) {
new X().negate().negate(); // results in a SomeNegatableClass, not an X
}
This isn't particularly serious for this application, but does cause trouble for other Haskell typeclasses, e.g. Equatable. There is no way of implementing a Java Equatable typeclass without using an additional object and sending an instance of that object around wherever we send values that need comparing, (e.g:
public interface Equatable<T> {
boolean equal (T a, T b);
}
public class MyClass
{
String str;
public static class MyClassEquatable implements Equatable<MyClass>
{
public boolean equal (MyClass a, MyClass b) {
return a.str.equals(b.str);
}
}
}
...
public <T> methodThatNeedsToEquateThings (T a, T b, Equatable<T> eq)
{
if (eq.equal (a, b)) { System.out.println ("they're equal!"); }
}
(In fact, this is exactly how Haskell implements type classes, but it hides the parameter passing from you so you don't need to figure out which implementation to send where)
Trying to do this with just plain Java interfaces leads to some counterintuitive results:
public interface Equatable<T extends Equatable<T>>
{
boolean equalTo (T other);
}
public MyClass implements Equatable<MyClass>
{
String str;
public boolean equalTo (MyClass other)
{
return str.equals(other.str);
}
}
public Another implements Equatable<MyClass>
{
public boolean equalTo (MyClass other)
{
return true;
}
}
....
MyClass a = ....;
Another b = ....;
if (b.equalTo(a))
assertTrue (a.equalTo(b));
....
You'd expect, due to the fact that equalTo really ought to be defined symmetrically, that if the if statement there compiles, the assertion would also compile, but it doesn't, because MyClass isn't equatable with Another even though the other way around is true. But with a Haskell Equatable type class, we know that if areEqual a b works, then areEqual b a is also valid. [1]
Another limitation of interfaces versus type classes is that a type class can provide a means of creating a value which implements the type class without having an existing value (e.g. the return operator for Monad), whereas for an interface you must already have an object of the type in order to be able to invoke its methods.
You ask whether there is a name for this limitation, but I'm not aware of one. It's simply because type classes are actually different to object-oriented interfaces, despite their similarities, because they are implemented in this fundamentally different way: an object is a subtype of its interface, thus carries around a copy of the interface's methods directly without modifying their definition, while a type class is a separate list of functions each of which is customised by substituting type variables. There is no subtype relationship between a type and a type class that has an instance for the type (a Haskell Integer isn't a subtype of Comparable, for example: there simply exists a Comparable instance that can be passed around whenever a function needs to be able to compare its parameters and those parameters happen to be Integers).
[1]: The Haskell == operator is actually implemented using a type class, Eq ... I haven't used this because operator overloading in Haskell can be confusing to people not familiar with reading Haskell code.
I interpret the question as
How can we implement ad-hoc polymorphism using typeclasses in Java?
You can do something very similar in Java, but without the type safety guarantees of Haskell - the solution presented below can throw errors at runtime.
Here is how you can do it:
Define interface that represents the typeclass
interface Negatable<T> {
T negate(T t);
}
Implement some mechanism that allows you to register instances of the typeclass for various types. Here, a static HashMap will do:
static HashMap<Class<?>, Negatable<?>> instances = new HashMap<>();
static <T> void registerInstance(Class<T> clazz, Negatable<T> inst) {
instances.put(clazz, inst);
}
#SuppressWarnings("unchecked")
static <T> Negatable<T> getInstance(Class<?> clazz) {
return (Negatable<T>)instances.get(clazz);
}
Define the normalize method that uses the above mechanism to get the appropriate instance based on the runtime class of the passed object:
public static <T> T normalize(T t) {
Negatable<T> inst = Negatable.<T>getInstance(t.getClass());
return inst.negate(inst.negate(t));
}
Register actual instances for various classes:
Negatable.registerInstance(Boolean.class, new Negatable<Boolean>() {
public Boolean negate(Boolean b) {
return !b;
}
});
Negatable.registerInstance(Integer.class, new Negatable<Integer>() {
public Integer negate(Integer i) {
return -i;
}
});
Use it!
System.out.println(normalize(false)); // Boolean `false`
System.out.println(normalize(42)); // Integer `42`
The main drawback is that, as already mentioned, the typeclass instance lookup can fail at runtime, not at compile-time (as in Haskell). Using a static hash map is suboptimal too, because it brings all the problems of a shared global variable, this could be mitigated with more sophisticated dependency injection mechanisms. Automatically generating typeclass instances from other typeclass instances, would require even more infrastructure (could be done in a library). But in principle, it implements ad-hoc polymorphism using typeclasses in Java.
Full code:
import java.util.HashMap;
class TypeclassInJava {
static interface Negatable<T> {
T negate(T t);
static HashMap<Class<?>, Negatable<?>> instances = new HashMap<>();
static <T> void registerInstance(Class<T> clazz, Negatable<T> inst) {
instances.put(clazz, inst);
}
#SuppressWarnings("unchecked")
static <T> Negatable<T> getInstance(Class<?> clazz) {
return (Negatable<T>)instances.get(clazz);
}
}
public static <T> T normalize(T t) {
Negatable<T> inst = Negatable.<T>getInstance(t.getClass());
return inst.negate(inst.negate(t));
}
static {
Negatable.registerInstance(Boolean.class, new Negatable<Boolean>() {
public Boolean negate(Boolean b) {
return !b;
}
});
Negatable.registerInstance(Integer.class, new Negatable<Integer>() {
public Integer negate(Integer i) {
return -i;
}
});
}
public static void main(String[] args) {
System.out.println(normalize(false));
System.out.println(normalize(42));
}
}
You're looking for generics, plus self typing. Self typing is the notion of generic placeholder that equates to the class of the instance.
However, self typing doesn't exist in java.
You can get close with generics, but it's clunky:
public interface Negatable<T> {
public T negate();
}
Then
public class MyBoolean implements Negatable<MyBoolean>{
#Override
public MyBoolean negate() {
//your impl
}
}
Some implications for implementers:
They must specify themselves when they implement the interface, e.g. MyBoolean implements Negatable<MyBoolean>
Extending MyBoolean would require one to override the negate method again.

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.

Assign a subclass of a Generic class to a super class of this class

I have couple of supplied interfaces
public interface Finder<S extends Stack<T>,T extends Item> {
public S find(S s, int a);
}
public interface Stack<T extends Item> {
Stack<T> getCopy();
}
and a class that implements the first:
public class SimpleFinder<S extends Stack<T>,T extends Item> implements Finder<S,T>{
public S find(S s, int a){
S stack = ....;
...
stack = s.getCopy(); \\Error: incompatible types
\\ required: S
\\ found: Stack<T>
.....
return stack;
}
}
If I cannot change any interface what would be the best course of action while keeping the implementation as generic as possible?
EDIT
Some other code which I cannot break instantiates SimpleFinder<ClassA,ClassB> so I should have two generic types in the implementation as well.
The problem is that obviously Stack<T> is not S extends Stack<T>. Java is strongly typed and won't let you do such things.
You can either cast to Stack<T>, in which case you will still get a warning about unchecked conversion. This means this conversion is unsafe.
public class SimpleFinder<S extends Stack<T>, T extends Item> implements Finder<S, T> {
#Override
public S find(S s, int a) {
Stack<T> stack = s.getCopy();
return (S) stack;
}
}
or simply use Stack<T> instead of S extends Stack<T>, which is my recommendation:
public class SimpleFinder<T extends Item> implements Finder<Stack<T>, T> {
#Override
public Stack<T> find(Stack<T> s, int a) {
Stack<T> stack = s.getCopy();
return stack;
}
}
Since you can't change the interfaces, you have no choice but to do brute cast.
In a more general discussion, what we need here is "self type", we want to say that a method invocation foo.bar() should return the static type of foo. Usually self type is wanted for fluent API where the method should return foo itself. In your case you want to return a new object.
In java there's no satisfactory answer for self type. One trick is through self referenced type paramter like Foo<T extends Foo<T>>, however it is very ugly, and it cannot really enforce that any subtype Bar must be a Foo<Bar>. And the trick won't help in your case at all.
Another trick may work
public interface Stack<T extends Item> {
<X extends Stack<T>> X getCopy();
}
here, the caller supplies the exact return type.
S stack = ....;
...
stack = s.getCopy();
// compiles, because X is inferred to be S
This trick helps to simplify call sites. However brute casts still exists, hidden in implementations of getCopy(). This trick is dangerous and caller must know what it is doing. Personally I wouldn't do it; it's better for force caller to do the cast.
As discussed in the comments, your design necessitates that the getCopy method return the "self type" - that is, a BlueStack<T> implementation would be expected to return a BlueStack<T> from its getCopy, and RedStack<T> should return a RedStack<T> etc.
Unfortunately, there is no way to express the "self type" in Java. As zhong.j.yu points out, a recursive type parameter comes close, for example:
//not recommended!
public interface Stack<S extends Stack<S, T>, T extends Item> {
S getCopy();
}
But as zhong.j.yu mentions this is unintuitive and would still fail to prevent a BlueStack<T> from "lying" and returning a RedStack<T> from its getCopy.
Instead, I recommend a redesign. Try decoupling the responsibility of copying stacks from the Stack type itself. For example:
public interface StackCopier<S extends Stack<T>, T extends Item> {
S copy(S original);
}
If implementations of StackCopier need access to private members of their respective Stacks, consider making them nested classes, for example:
class BlueStack<T extends Item> implements Stack<T> {
...
static class Copier<T extends Item> implements StackCopier<BlueStack<T>, T> {
#Override
public BlueStack<T> copy(BlueStack<T> original) {
...
}
}
Of course SimpleFinder would need to be changed to either have a StackCopier<S, T> field or take one as a new parameter of find:
private final StackCopier<S, T> copier = ...;
public S find(S stack, int a) {
S stackCopy = copier.copy(stack);
...
return stackCopy;
}
Your type S is a subtype of Stack<T> but the copy method is upcasting it to a Stack<T> that may be any subtype of Stack<T>.
You will have to cast the result of copy to S
public class SimpleFinder<S extends Stack<T>,T extends Item> implements Finder<S,T>{
public S find(S s, int a){
Stack<T> stack = ....;
...
stack = s.getCopy();
.....
return (S) stack;
}
}
should work. Keep in mind that stack must be a Stack<T> and not S to match getCopy() return type. I would expect S type to be Ok, since it extends Stack<T>, but implementing it this is the behavior that I'm observing.

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.

Abstract Generic class

I have the following class :
public abstract class Step {
public abstract <S,T> S makeAStep(S currentResult, T element);
}
and I'm trying to Implement it so it will take two int's and return the sum of them , something like this :
public class sumOfInts extends Step {
public <Integer,Integer> Integer makeAStep(Integer currentResult, Integer element){
return currentResult + element;
}
}
but I get the following error :
The type sumOfInts must implement the inherited abstract method Step.makeAStep(S, T)
please help me (I need it for my programming languages course homework)
I asking very kindly to write me a code that does what I want to accomplish which wont
have any errors or warnings
thanks in front
public abstract class Step<S,T> {
public abstract S makeAStep(S currentResult, T element);
}
public class SumOfInts extends Step<Integer,Integer> {
// etc.
I agree with Jonathan's answer.
There is also another possibility, given below, that keeps the type parameters on the method itself.
It's only theory in this case, because the class and method names suggest that this has no meaning for this example.
So I change the names for my example:
public abstract class Step {
public abstract <S,T> String makeAStep(S first, T second);
}
public class ConcatTwo extends Step {
public <S, T> String makeAStep(S first, T second){
return String.valueOf(first) + String.valueOf(second);
}
}
Note : This works because the operation uses String.valueOf(Object), that works for any type (all subclass Object). For another operation, we would have to restrict S and T, using something like
S extend Integer for example.

Categories

Resources