How can I write a typesafe Java method that returns either something of class a or something of class b? For example:
public ... either(boolean b) {
if (b) {
return new Integer(1);
} else {
return new String("hi");
}
}
What is the cleanest way?
( The only thing that comes to my mind is using exceptions which is obviously bad, as it is abusing a error-handling mechanism for a general language feature ...
public String either(boolean b) throws IntException {
if (b) {
return new String("test");
} else {
throw new IntException(new Integer(1));
}
}
)
My general formula for simulating algebraic data types is:
The type is an abstract base class, and the constructors are subclasses of that
The data for each constructor are defined in each subclass. (This allows constructors with different numbers of data to work correctly. It also removes the need to maintain invariants like only one variable is non-null or stuff like that).
The constructors of the subclasses serve to construct the value for each constructor.
To deconstruct it, one uses instanceof to check the constructor, and downcast to the appropriate type to get the data.
So for Either a b, it would be something like this:
abstract class Either<A, B> { }
class Left<A, B> extends Either<A, B> {
public A left_value;
public Left(A a) { left_value = a; }
}
class Right<A, B> extends Either<A, B> {
public B right_value;
public Right(B b) { right_value = b; }
}
// to construct it
Either<A, B> foo = new Left<A, B>(some_A_value);
Either<A, B> bar = new Right<A, B>(some_B_value);
// to deconstruct it
if (foo instanceof Left) {
Left<A, B> foo_left = (Left<A, B>)foo;
// do stuff with foo_left.a
} else if (foo instanceof Right) {
Right<A, B> foo_right = (Right<A, B>)foo;
// do stuff with foo_right.b
}
Here is a statically checked type-safe solution; this means you cannot create runtime errors. Please read the previous sentence in the way it is meant. Yes, you can provoke exceptions in some way or the other...
It's pretty verbose, but hey, it's Java!
public class Either<A,B> {
interface Function<T> {
public void apply(T x);
}
private A left = null;
private B right = null;
private Either(A a,B b) {
left = a;
right = b;
}
public static <A,B> Either<A,B> left(A a) {
return new Either<A,B>(a,null);
}
public static <A,B> Either<A,B> right(B b) {
return new Either<A,B>(null,b);
}
/* Here's the important part: */
public void fold(Function<A> ifLeft, Function<B> ifRight) {
if(right == null)
ifLeft.apply(left);
else
ifRight.apply(right);
}
public static void main(String[] args) {
Either<String,Integer> e1 = Either.left("foo");
e1.fold(
new Function<String>() {
public void apply(String x) {
System.out.println(x);
}
},
new Function<Integer>() {
public void apply(Integer x) {
System.out.println("Integer: " + x);
}
});
}
}
You might want to look at Functional Java and Tony Morris' blog.
Here is the link to the implementation of Either in Functional Java. The fold in my example is called either there. They have a more sophisticated version of fold, that is able to return a value (which seems appropriate for functional programming style).
You can have a close correspondence with Haskell by writing a generic class Either, parametric on two types L and R with two constructors (one taking in an L, and one taking in an R) and two methods L getLeft() and R getRight() such that they either return the value passed when constructing, or throw an exception.
The suggestions already provided, although feasible, are not complete as they rely on some null references and effectively make "Either" masquerade as a tuple of values. A disjoint sum is obviously one type or the other.
I'd suggest having a look at the implementation of FunctionalJava's Either as an example.
The big thing is not to try to write in one language whilst writing in another. Generally in Java you want to put the behaviour in the object, rather than having a "script" running outside with encapsulation destroyed by get methods. There is no context for making that kind of suggestion here.
One safe way of dealing with this particular little fragment is to write it as a callback. Similar to a very simple visitor.
public interface Either {
void string(String value);
void integer(int value);
}
public void either(Either handler, boolean b) throws IntException {
if (b) {
handler.string("test");
} else {
handler.integer(new Integer(1));
}
}
You may well want to implement with pure functions and return a value to the calling context.
public interface Either<R> {
R string(String value);
R integer(int value);
}
public <R> R either(Either<? extends R> handler, boolean b) throws IntException {
return b ?
handler.string("test") :
handler.integer(new Integer(1));
}
(Use Void (capital 'V') if you want to get back to being uninterested in the return value.)
I've implemented it in a Scala-like fashion in the following way. It's a little verbose (it is Java, after all :)) but it's type safe.
public interface Choice {
public enum Type {
LEFT, RIGHT
}
public Type getType();
interface Get<T> {
T value();
}
}
public abstract class Either<A, B> implements Choice {
private static class Base<A, B> extends Either<A, B> {
#Override
public Left leftValue() {
throw new UnsupportedOperationException();
}
#Override
public Right rightValue() {
throw new UnsupportedOperationException();
}
#Override
public Type getType() {
throw new UnsupportedOperationException();
}
}
public abstract Left leftValue();
public abstract Right rightValue();
public static <A, B> Either<A, B> left(A value) {
return new Base<A, B>().new Left(value);
}
public static <A, B> Either<A, B> right(B value) {
return new Base<A, B>().new Right(value);
}
public class Left extends Either<A, B> implements Get<A> {
private A value;
public Left(A value) {
this.value = value;
}
#Override
public Type getType() {
return Type.LEFT;
}
#Override
public Left leftValue() {
return Left.this;
}
#Override
public Right rightValue() {
return null;
}
#Override
public A value() {
return value;
}
}
public class Right extends Either<A, B> implements Get<B> {
private B value;
public Right(B value) {
this.value = value;
}
#Override
public Left leftValue() {
return null;
}
#Override
public Right rightValue() {
return this;
}
#Override
public Type getType() {
return Type.RIGHT;
}
#Override
public B value() {
return value;
}
}
}
Then you can pass Either<A,B> instances around on your code. The Type enum is mainly used on switch statements.
Creating Either values is simple as:
Either<A, B> underTest;
A value = new A();
underTest = Either.left(value);
assertEquals(Choice.Type.LEFT, underTest.getType());
assertSame(underTest, underTest.leftValue());
assertNull(underTest.rightValue());
assertSame(value, underTest.leftValue().value());
Or, in the typical situation where it is used instead of exceptions,
public <Error, Result> Either<Error,Result> doSomething() {
// pseudo code
if (ok) {
Result value = ...
return Either.right(value);
} else {
Error errorMsg = ...
return Either.left(errorMsg);
}
}
// somewhere in the code...
Either<Err, Res> result = doSomething();
switch(result.getType()) {
case Choice.Type.LEFT:
// Handle error
Err errorValue = result.leftValue().value();
break;
case Choice.Type.RIGHT:
// Process result
Res resultValue = result.rightValue().value();
break;
}
Hope it helps.
From http://blog.tmorris.net/posts/maybe-in-java/ I learned that you can make the outer class's constructor private so only nested classes can subclass it. This trick is just as type safe as the best above, but much less verbose, works for any ADT you want like Scala's case class.
public abstract class Either<A, B> {
private Either() { } // makes this a safe ADT
public abstract boolean isRight();
public final static class Left<L, R> extends Either<L, R> {
public final L left_value;
public Left(L l) { left_value = l; }
public boolean isRight() { return false; }
}
public final static class Right<L, R> extends Either<L, R> {
public final R right_value;
public Right(R r) { right_value = r; }
public boolean isRight() { return true; }
}
}
(started from top answer's code and style)
Note that:
The finals on the subclass are optional. Without them you can subtype Left and Right, but still not Either directly. Thus without the finals Either has limited width but unbounded depth.
With ADTs like this, I see no reason to jump on the whole anti-instanceof bandwagon. A boolean works for Maybe or Either, but in general instanceof is your best and only option.
Thanks to Derive4J algebraic data types are now very easy in Java. All you have to do is create the following class:
import java.util.function.Function;
#Data
public abstract class Either<A, B> {
Either(){}
/**
* The catamorphism for either. Folds over this either breaking into left or right.
*
* #param left The function to call if this is left.
* #param right The function to call if this is right.
* #return The reduced value.
*/
public abstract <X> X either(Function<A, X> left, Function<B, X> right);
}
And Derive4J will take care of creating constructors for the left and rights cases, as well as a pattern matching syntax alla Haskell, mapper methods for each sides, and more.
There is a stand-alone implementation of Either for Java 8 in a small library, "ambivalence": http://github.com/poetix/ambivalence
It is closest to the Scala standard implementation - for example, it provides left and right projections for map and hashMap operations.
There is no direct access to the left or right values; rather, you join the two types by providing lambdas to map them into a single result type:
Either<String, Integer> either1 = Either.ofLeft("foo");
Either<String, Integer> either2 = Either.ofRight(23);
String result1 = either1.join(String::toUpperCase, Object::toString);
String result2 = either2.join(String::toUpperCase, Object::toString);
You can get it from Maven central:
<dependency>
<groupId>com.codepoetics</groupId>
<artifactId>ambivalence</artifactId>
<version>0.2</version>
</dependency>
You don't need to settle with the instanceof checks or redundant fields. Surprisingly enough, Java's type system provides enough features to simulate the sum types cleanly.
Background
First of all, do you know that any data type can be encoded with just functions? It's called Church encoding. E.g., using the Haskell signature, the Either type could be defined as follows:
type Either left right =
forall output. (left -> output) -> (right -> output) -> output
You can interpret it as "given a function on the left value and a function on the right value, produce the result of either of them".
Definition
Expanding on this idea, in Java we can define an interface called Matcher, which includes both functions and then define the Sum type in terms of how to pattern-match on it. Here's the complete code:
/**
* A sum class which is defined by how to pattern-match on it.
*/
public interface Sum2<case1, case2> {
<output> output match(Matcher<case1, case2, output> matcher);
/**
* A pattern-matcher for 2 cases.
*/
interface Matcher<case1, case2, output> {
output match1(case1 value);
output match2(case2 value);
}
final class Case1<case1, case2> implements Sum2<case1, case2> {
public final case1 value;
public Case1(case1 value) {
this.value = value;
}
public <output> output match(Matcher<case1, case2, output> matcher) {
return matcher.match1(value);
}
}
final class Case2<case1, case2> implements Sum2<case1, case2> {
public final case2 value;
public Case2(case2 value) {
this.value = value;
}
public <output> output match(Matcher<case1, case2, output> matcher) {
return matcher.match2(value);
}
}
}
Usage
And then you can use it like this:
import junit.framework.TestCase;
public class Test extends TestCase {
public void testSum2() {
assertEquals("Case1(3)", longOrDoubleToString(new Sum2.Case1<>(3L)));
assertEquals("Case2(7.1)", longOrDoubleToString(new Sum2.Case2<>(7.1D)));
}
private String longOrDoubleToString(Sum2<Long, Double> longOrDouble) {
return longOrDouble.match(new Sum2.Matcher<Long, Double, String>() {
public String match1(Long value) {
return "Case1(" + value.toString() + ")";
}
public String match2(Double value) {
return "Case2(" + value.toString() + ")";
}
});
}
}
With this approach you can even find a direct resemblance of pattern-matching in such languages as Haskell and Scala.
Library
This code is distributed as part of my library of composite types (Sums and Products, aka Unions and Tuples) of multiple arities. It's on GitHub:
https://github.com/nikita-volkov/composites.java
Since you've tagged Scala, I'll give a Scala answer. Just use the existing Either class. Here's an example usage:
def whatIsIt(flag: Boolean): Either[Int,String] =
if(flag) Left(123) else Right("hello")
//and then later on...
val x = whatIsIt(true)
x match {
case Left(i) => println("It was an int: " + i)
case Right(s) => println("It was a string: " + s)
}
This is completely type-safe; you won't have problems with erasure or anything like that...
And if you simply can't use Scala, at least use this as an example of how you can implement your own Either class.
The closest I can think of is a wrapper around both values that lets you check which value is set and retrieve it:
class Either<TLeft, TRight> {
boolean isLeft;
TLeft left;
TRight right;
Either(boolean isLeft, TLeft left1, TRight right) {
isLeft = isLeft;
left = left;
this.right = right;
}
public boolean isLeft() {
return isLeft;
}
public TLeft getLeft() {
if (isLeft()) {
return left;
} else {
throw new RuntimeException();
}
}
public TRight getRight() {
if (!isLeft()) {
return right;
} else {
throw new RuntimeException();
}
}
public static <L, R> Either<L, R> newLeft(L left, Class<R> rightType) {
return new Either<L, R>(true, left, null);
}
public static <L, R> Either<L, R> newRight(Class<L> leftType, R right) {
return new Either<L, R>(false, null, right);
}
}
class Main {
public static void main(String[] args) {
Either<String,Integer> foo;
foo = getString();
foo = getInteger();
}
private static Either<String, Integer> getInteger() {
return Either.newRight(String.class, 123);
}
private static Either<String, Integer> getString() {
return Either.newLeft("abc", Integer.class);
}
}
Based on the answer by Riccardo, following code snippet worked for me:
public class Either<L, R> {
private L left_value;
private R right_value;
private boolean right;
public L getLeft() {
if(!right) {
return left_value;
} else {
throw new IllegalArgumentException("Left is not initialized");
}
}
public R getRight() {
if(right) {
return right_value;
} else {
throw new IllegalArgumentException("Right is not initialized");
}
}
public boolean isRight() {
return right;
}
public Either(L left_v, Void right_v) {
this.left_value = left_v;
this.right = false;
}
public Either(Void left_v, R right_v) {
this.right_value = right_v;
right = true;
}
}
Usage:
Either<String, Integer> onlyString = new Either<String, Integer>("string", null);
Either<String, Integer> onlyInt = new Either<String, Integer>(null, new Integer(1));
if(!onlyString.isRight()) {
String s = onlyString.getLeft();
}
Change your design so that you don't need this rather absurd feature. Anything you'd do with the return value would require some sort of if/else construct. It would just be very, very ugly.
From a quick Googling, it seems to me that the only thing Haskell's Either is commonly used for is error reporting anyway, so it looks like exceptions are actually to correct replacement.
Related
I'm trying to understand how Either is implemented. I've gotten stuck at chaining together multiple functions in a way that allows returning a different Left value during flatMap. I can't work out how it is possible within the type system.
Minimal Either example code:
public class Either<A,B> {
public final A left;
public final B right;
private Either(A a, B b) {
left = a;
right = b;
}
public static <A, B> Either<A, B> left(A a) {
return new Either<>(a, null);
}
public static <A, B> Either<A, B> right(B b) {
return new Either<>(null, b);
}
public <C> Either<A, C> flatMap(Function<B, Either<A,C>> f) {
if (this.isRight()) return f.apply(this.right);
else return Either.left(this.left);
}
// map and other useful functions....
I originally thought I'd be able to map to different Left values, which would allow returning the relevant error at each point.
So, for instance, given these functions:
public static Either<Foo, String> doThing() {
return Either.right("foo");
}
public static Either<Bar, String> doThing2(String text) {
return (text.equals("foo"))
? Either.right("Yay!")
: Either.left(new Bar("Grr..."));
}
public static Either<Baz, String> doThing3() {
return (text.equals("Yay!"))
? Either.right("Hooray!")
: Either.left(new Baz("Oh no!!"));
}
I thought I'd be able to do
doThing().flatMap(x -> doThing2()).flatMap(y -> doThing3())
However, the compiler flags this as impossible.
After some studying of the code, I realized that it's due to my <A,B> generic parameters.
flatMap has two different cases:
the case where we map the right side
the case where we pass through the left value
So, if my goal is to enable sometimes returning different Left values from flatMap, then my two generic variables <A,B> don't work, because if case 1 executes and my function changes A, then case 2 is invalid, because A != A'. The act of applying a function to the right side may have changed the Left side to a different type.
All this leads me to these questions:
Is my expectation for the behavior of the Either type incorrect?
Is it possible to return different Left types during a flatMap operation?
if so, how do you get the types to work out?
There isn't a sensible flatMap() function like you want, due to parametricity. Consider:
Either<Foo, String> e1 = Either.left(new Foo());
Either<Bar, String> e2 = foo.flatMap(x -> doThing2());
Bar bar = e2.left; // Where did this come from???
flatMap() itself would have had to invent a Bar instance somehow. If you start writing a flatMap() that can change both types, you'll see the issue more clearly:
public <C, D> Either<C, D> flatMap(Function<B, Either<C, D>> f) {
if (this.isRight()) {
return f.apply(this.right);
} else {
// Error: can't convert A to C
return Either.left(this.left);
}
}
You can, but your old Left has to be a subtype of or equal to the new Left, so it can be cast up. I'm not very familiar with Java's syntax, but the Scala implementation looks like:
def flatMap[A1 >: A, B1](f: B => Either[A1, B1]): Either[A1, B1] = this match {
case Right(b) => f(b)
case _ => this.asInstanceOf[Either[A1, B1]]
}
Here the A1 >: A designates A as a subtype of A1. I know Java has an <A extends A1> syntax, but I'm not sure it can be used to describe the constraint on A1, as we need in this case.
Regarding your usage of Either (doThing(...)) it seems your flat mapping isn't sufficient. I assume you want your flat mapping work like for Optional<T>.
The mapper ofOptional.flatMap takes a value of kind of T and returns an Optional<U> where U is a generic type parameter of this method. But Optional has one generic type parameter T whereas Either has two: A and B. So if you want to flat map an Either<A,B> either it isn't sufficient to use one mapping.
One mapping what should it map? "The value which isn't null" you would say - wouldn't you? Ok but you know that first at runtime. Your flatMap method is defined at compile time. Therefore you have to provide a mapping for each case.
You choose <C> Either<A, C> flatMap(Function<B, Either<A, C>> f). This mapping uses a value of type B as input. That means if the mapped Either either is !either.isRight() all following mappings would return an Either.left(a) where a is the value of the very first Either.left(a). So actually only an Either either where either.isRight() could be mapped to another value. And it has to be either.isRight() from the beginning. This means also that once an Either<A,B> either is created all flat mappings will result in a kind of Either<A,?>. So the current flatMap restricts an Either either to keep its left generic type. Is this what you supposed to do?
If you want to flat map an Either either without restrictions you need mappings for both cases: either.isRight() and !either.isRight(). This will allow you to continue the flat mapping in both directions.
I did it this way:
public class Either<A, B> {
public final A left;
public final B right;
private Either(A a, B b) {
left = a;
right = b;
}
public boolean isRight() {
return right != null;
}
#Override
public String toString() {
return isRight() ?
right.toString() :
left.toString();
}
public static <A, B> Either<A, B> left(A a) {
return new Either<>(a, null);
}
public static <A, B> Either<A, B> right(B b) {
return new Either<>(null, b);
}
public <C, D> Either<C, D> flatMap(Function<A, Either<C, D>> toLeft, Function<B, Either<C, D>> toRight) {
if (this.isRight()) {
return toRight.apply(this.right);
} else {
return toLeft.apply(this.left);
}
}
public static void main(String[] args) {
Either<String, String> left = Either.left(new Foo("left"))
.flatMap(l -> Either.right(new Bar(l.toString() + ".right")), r -> Either.left(new Baz(r.toString() + ".left")))
.flatMap(l -> Either.left(l.toString() + ".left"), r -> Either.right(r.toString() + ".right"));
System.out.println(left); // left.right.right
Either<String, String> right = Either.right(new Foo("right"))
.flatMap(l -> Either.right(new Bar(l.toString() + ".right")), r -> Either.left(new Baz(r.toString() + ".left")))
.flatMap(l -> Either.left(l.toString() + ".left"), r -> Either.right(r.toString() + ".right"))
.flatMap(l -> Either.right(l.toString() + ".right"), r -> Either.left(r.toString() + ".left"));
System.out.println(right); // right.left.left.right
}
private static class Foo {
private String s;
public Foo(String s) {
this.s = s;
}
#Override
public String toString() {
return s;
}
}
private static class Bar {
private String s;
public Bar(String s) {
this.s = s;
}
#Override
public String toString() {
return s;
}
}
private static class Baz {
private String s;
public Baz(String s) {
this.s = s;
}
#Override
public String toString() {
return s;
}
}
}
Answering your question: Yes it is possible to construct an Either returning a different left value. But I think your intent was to know how to get a proper working Either.
Is there any way to define a sum type in Java? Java seems to naturally support product types directly, and I thought enums might allow it to support sum types, and inheritance looks like maybe it could do it, but there is at least one case I can't resolve.
To elaborate, a sum type is a type which can have exactly one of a set of different types, like a tagged union in C.
In my case, I'm trying to implement haskell's Either type in Java:
data Either a b = Left a | Right b
but at the base level I'm having to implement it as a product type, and just ignore one of its fields:
public class Either<L,R>
{
private L left = null;
private R right = null;
public static <L,R> Either<L,R> right(R right)
{
return new Either<>(null, right);
}
public static <L,R> Either<L,R> left(L left)
{
return new Either<>(left, null);
}
private Either(L left, R right) throws IllegalArgumentException
{
this.left = left;
this.right = right;
if (left != null && right != null)
{
throw new IllegalArgumentException("An Either cannot be created with two values");
}
if (left == right)
{
throw new IllegalArgumentException("An Either cannot be created without a value");
}
}
.
.
.
}
I tried implementing this with inheritance, but I have to use a wildcard type parameter, or equivalent, which Java generics won't allow:
public class Left<L> extends Either<L,?>
I haven't used Java's Enums much, but while they seem the next best candidate, I'm not hopeful.
At this point, I think this might only be possible by type-casting Object values, which I would hope to avoid entirely, unless there's a way to do it once, safely, and be able to use that for all sum types.
Make Either an abstract class with no fields and only one constructor (private, no-args, empty) and nest your "data constructors" (left and right static factory methods) inside the class so that they can see the private constructor but nothing else can, effectively sealing the type.
Use an abstract method either to simulate exhaustive pattern matching, overriding appropriately in the concrete types returned by the static factory methods. Implement convenience methods (like fromLeft, fromRight, bimap, first, second) in terms of either.
import java.util.Optional;
import java.util.function.Function;
public abstract class Either<A, B> {
private Either() {}
public abstract <C> C either(Function<? super A, ? extends C> left,
Function<? super B, ? extends C> right);
public static <A, B> Either<A, B> left(A value) {
return new Either<A, B>() {
#Override
public <C> C either(Function<? super A, ? extends C> left,
Function<? super B, ? extends C> right) {
return left.apply(value);
}
};
}
public static <A, B> Either<A, B> right(B value) {
return new Either<A, B>() {
#Override
public <C> C either(Function<? super A, ? extends C> left,
Function<? super B, ? extends C> right) {
return right.apply(value);
}
};
}
public Optional<A> fromLeft() {
return this.either(Optional::of, value -> Optional.empty());
}
}
Pleasant and safe! No way to screw it up. Because the type is effectively sealed, you can rest assured that there will only ever be two cases, and every operation ultimately must be defined in terms of the either method, which forces the caller to handle both of those cases.
Regarding the problem you had trying to do class Left<L> extends Either<L,?>, consider the signature <A, B> Either<A, B> left(A value). The type parameter B doesn't appear in the parameter list. So, given a value of some type A, you can get an Either<A, B> for any type B.
A standard way of encoding sum types is Boehm–Berarducci encoding (often referred to by the name of its cousin, Church encoding) which represents an algebraic data type as its eliminator, i.e., a function that does pattern-matching. In Haskell:
left :: a -> (a -> r) -> (b -> r) -> r
left x l _ = l x
right :: b -> (a -> r) -> (b -> r) -> r
right x _ r = r x
match :: (a -> r) -> (b -> r) -> ((a -> r) -> (b -> r) -> r) -> r
match l r k = k l r
-- Or, with a type synonym for convenience:
type Either a b r = (a -> r) -> (b -> r) -> r
left :: a -> Either a b r
right :: b -> Either a b r
match :: (a -> r) -> (b -> r) -> Either a b r -> r
In Java this would look like a visitor:
public interface Either<A, B> {
<R> R match(Function<A, R> left, Function<B, R> right);
}
public final class Left<A, B> implements Either<A, B> {
private final A value;
public Left(A value) {
this.value = value;
}
public <R> R match(Function<A, R> left, Function<B, R> right) {
return left.apply(value);
}
}
public final class Right<A, B> implements Either<A, B> {
private final B value;
public Right(B value) {
this.value = value;
}
public <R> R match(Function<A, R> left, Function<B, R> right) {
return right.apply(value);
}
}
Example usage:
Either<Integer, String> result = new Left<Integer, String>(42);
String message = result.match(
errorCode -> "Error: " + errorCode.toString(),
successMessage -> successMessage);
For convenience, you can make a factory for creating Left and Right values without having to mention the type parameters each time; you can also add a version of match that accepts Consumer<A> left, Consumer<B> right instead of Function<A, R> left, Function<B, R> right if you want the option of pattern-matching without producing a result.
Alright, so the inheritance solution is definitely the most promising. The thing we would like to do is class Left<L> extends Either<L, ?>, which we unfortunately cannot do because of Java's generic rules. However, if we make the concessions that the type of Left or Right must encode the "alternate" possibility, we can do this.
public class Left<L, R> extends Either<L, R>`
Now, we would like to be able to convert Left<Integer, A> to Left<Integer, B>, since it doesn't actually use that second type parameter. We can define a method to do this conversion internally, thus encoding that freedom into the type system.
public <R1> Left<L, R1> phantom() {
return new Left<L, R1>(contents);
}
Complete example:
public class EitherTest {
public abstract static class Either<L, R> {}
public static class Left<L, R> extends Either<L, R> {
private L contents;
public Left(L x) {
contents = x;
}
public <R1> Left<L, R1> phantom() {
return new Left<L, R1>(contents);
}
}
public static class Right<L, R> extends Either<L, R> {
private R contents;
public Right(R x) {
contents = x;
}
public <L1> Right<L1, R> phantom() {
return new Right<L1, R>(contents);
}
}
}
Of course, you'll want to add some functions for actually accessing the contents, and for checking whether a value is Left or Right so you don't have to sprinkle instanceof and explicit casts everywhere, but this should be enough to get started, at the very least.
Inheritance can be used to emulate sum types (Disjoint unions), but there are a few issues you need to deal with:
You need to take care to keep others from adding new cases to your type. This is especially important if you want to exhaustively handle every case you might encounter. It's possible with a non-final super class, and package-private constructor.
The lack of pattern patching makes it quite difficult to consume a value of this type. If you want compiler-checked way to guarantee that you've exhaustively handled all cases, you need to implement a match function yourself.
You're forced into one of two styles of API, neither of which are ideal:
All cases implement a common API, throwing errors on API they don't support themselves. Consider Optional.get(). Ideally, this method would only be available on a disjoint type who's value is known to be some rather than none. But there's no way to do that, so it's an instance member of a general Optional type. It throws NoSuchElementException if you call it on an optional whose "case" is "none".
Each case has a unique API that tells you exactly what it's capable of, but that requires a manual type check and cast every time you wish to call one of these subclass-specific methods.
Changing "cases" requires new object allocation (and adds pressure on the GC if done often).
TL;DR: Functional programming in Java is not a pleasant experience.
Let me suggest a very different solution, that does not make use of inheritance / abstract classes / interfaces. On the downside, it requires some effort for each new "sum type" defined. However, I think it has many advantages : it is safe, it only uses basic concepts, it feels natural to use, and allows for more than 2 "subtypes".
Here is a proof of concept for binary trees because it's more practical than "Either", but you can just use the comments as the guideline to build your own sum type.
public class Tree {
// 1) Create an enum listing all "subtypes" (there may be more than 2)
enum Type { Node, Leaf }
// 2) Create a static class for each subtype (with the same name for clarity)
public static class Node {
Tree l,r;
public Node(Tree l, Tree r) {
this.l = l;
this.r = r;
}
}
public static class Leaf {
int label;
public Leaf(int label) {
this.label = label;
}
}
// 3) Each instance must have:
// One variable to indicate which subtype it corresponds to
Type type;
// One variable for each of the subtypes (only one will be different from null)
Leaf leaf;
Node node;
// 4) Create one constructor for each subtype (it could even be private)
public Tree(Node node) {
this.type = Type.Node;
this.node = node;
}
// 5) Create one "factory" method for each subtype (not mandatory but quite convenient)
public static Tree newNode(Tree l, Tree r) {
return new Tree(new Node(l,r));
}
public Tree(Leaf leaf) {
this.type = Type.Leaf;
this.leaf = leaf;
}
public static Tree newLeaf(int label) {
return new Tree(new Leaf(label));
}
// 6) Create a generic "matching" function with one argument for each subtype
// (the constructors ensure that no "null pointer exception" can be raised)
public <T> T match(Function<Node,T> matchNode, Function<Leaf,T> matchLeaf) {
switch (type) {
case Node:
return matchNode.apply(node);
case Leaf:
return matchLeaf.apply(leaf);
}
return null;
}
// 7) Have fun !
// Note that matchings are quite natural to write.
public int size() {
return match(
node -> 1 + node.l.size() + node.r.size(),
leaf -> 1
);
}
public String toString() {
return match(
node -> {
String sl = node.l.toString();
String sr = node.r.toString();
return "Node { "+sl+" , "+sr+" }";
},
leaf -> "Leaf: "+leaf.label
);
}
public static void main(String [] args) {
Tree node1 = Tree.newNode(Tree.newLeaf(1),Tree.newLeaf(2));
Tree node2 = Tree.newNode(node1,Tree.newLeaf(3));
System.out.println(node2.size());
System.out.println(node2);
}
}
Feel free to express criticism, I'm genuinely interested in this topic and will be happy to learn more.
How about
import java.util.Optional;
public interface Either<L, R> {
default Optional<L> left() { return Optional.empty();}
default Optional<R> right() { return Optional.empty();}
static <L, R> Either<L, R> fromLeft(L left) {
return new Either<L, R>() {
#Override public Optional<L> left() { return Optional.of(left); }
};
}
static <L, R> Either<L, R> fromRight(R right) {
return new Either<L, R>() {
#Override public Optional<R> right() { return Optional.of(right); }
};
}
}
The difference to other solutions proposed here is not deep, but stylistic.
I have an interface:
public interface ITransformer<S,T>{
public void transform(S source,T target);
default String getTransformerName(){
Class<S> s;
Class<T> t;
return s.getName() + t.getName(); //*********
}
}
the error message the starred line:
The local variable s may not have been initialized
The local variable t may not have been initialized
I would like to use this method to return a string with [S.classname][T.classname] . Please let me know how to achieve this or is this impossible to do at interface ?
Update: Jan 12
My purpose of doing this is due to the fact that this class will be in framework and I want to reduce the human error as much as possible.. I am changing the code as follows:
public interface ITransformer<S,T>{
public void transform(S source,T target);
public FieldEntry<S, T> getTransformerName();
}
public class FieldEntry<S,T> implements Comparable<FieldEntry> {
private Class<S> s;
private Class<T> t;
public FieldEntry(Class<S> s,Class<T> t){
this.s = s;
this.t = t;
}
public String getEntryName(){
return s.getName() + t.getName();
}
#Override
public int compareTo(FieldEntry entry) {
if(entry == null) throw new IllegalArgumentException("The argument to compare cannot be null!");
return entry.getEntryName().compareTo(this.getEntryName());
}
}
In order to demonstrate why this can’t work, you may change your class to
public interface ITransformer<S,T>{
public void transform(S source,T target);
static <In,Out> ITransformer<In,Out> noOp() {
return (source,target) -> {};
}
static void main(String... arg) {
ITransformer<String,Integer> t1 = noOp();
ITransformer<Long,Thread> t2 = noOp();
System.out.println(t1 == (Object)t2);
}
}
Running this will print true. In other words, both functions are represented by the same instances, so there can’t be and property allowing to recognize their different type.
Generally, when two functions (lambda expressions or method references) exhibit the same behavior, a JVM may represent them by the same implementation type or even the same instance.
Even for non-interface classes, this doesn’t work due to Type Erasure. It only works when you have a reifiable (i.e. non-generic) type extending or implementing a generic type.
It's a little bit dangerous and I wouldn't used this in production (because you should cover in your code all possible use cases of your interface), but you can use reflection for it:
public interface ITransformer<S, T> {
public void transform(S source, T target);
default String getTransformerName() {
Type[] genericInterfaces = this.getClass().getGenericInterfaces();
ParameterizedType parameterizedType = null;
for (Type genericInterface : genericInterfaces) {
if (genericInterface instanceof ParameterizedType) {
ParameterizedType paramInterface = (ParameterizedType) genericInterface;
if (paramInterface.getRawType().equals(ITransformer.class)) {
parameterizedType = paramInterface;
break;
}
}
}
if (parameterizedType == null) {
throw new IllegalStateException("!");
}
return parameterizedType.getActualTypeArguments()[0].getTypeName() + parameterizedType.getActualTypeArguments()[1].getTypeName();
}
}
public class StringToIntegerTransfomer implements ITransformer<String, Integer> {
#Override
public void transform(String source, Integer target) {
}
}
public interface StringToNumberTransfomer<T extends Number> extends ITransformer<String, T> {
}
public class StringToLongTransfomer implements StringToNumberTransfomer<Long>, ITransformer<String, Long> {
#Override
public void transform(String source, Long target) {
}
}
#Test
public void test() {
ITransformer<String, Integer> intTransformer = new StringToIntegerTransfomer();
ITransformer<String, Long> longTransformer = new StringToLongTransfomer();
ITransformer<String, String> stringTransformer = new ITransformer<String, String>() {
#Override
public void transform(String source, String target) {
}
};
ITransformer<String, Double> doubleTransformer = new StringToNumberTransfomer<Double>() {
#Override
public void transform(String source, Double target) {
}
};
System.out.println(String.format("intTransformer: %s", intTransformer.getTransformerName()));
System.out.println(String.format("longTransformer: %s", longTransformer.getTransformerName()));
System.out.println(String.format("stringTransformer: %s", stringTransformer.getTransformerName()));
System.out.println(String.format("doubleTransformer: %s", doubleTransformer.getTransformerName()));
}
Output for this snippet:
intTransformer: java.lang.Stringjava.lang.Integer
longTransformer: java.lang.Stringjava.lang.Long
stringTransformer: java.lang.Stringjava.lang.String
java.lang.IllegalStateException: !
This code has one restriction, you should say implements ITransformer<S, T> for all implementations of ITransformer. That why I have got IllegalStateException for this line ITransformer<String, Double> doubleTransformer = new StringToNumberTransfomer<Double>(). But you can improve this code.
Better option is to use some base implementation of interface and pass source and target classes into constructor:
public interface ITransformer<S, T> {
void transform(S source, T target);
String getTransformerName();
}
public abstract class BaseITransformer<S, T> implements ITransformer<S, T> {
private final Class<S> sourceClass;
private final Class<T> targetClass;
public BaseITransformer(Class<S> sourceClass, Class<T> targetClass) {
this.sourceClass = sourceClass;
this.targetClass = targetClass;
}
public String getTransformerName() {
return sourceClass.getName() + targetClass.getName();
}
}
In Java it is impossible to get a Class<S>, unless you already know which class S is, or something else that knows which class S is gives you one.
I have a (for me) complex Java generics problem. I read through some documentation and understand some but certainly not all of what I should. Basically, for me, trying to solve it would result in try and error.
In the following, I give a condensed example of my code, once without any generics (so one can hopefully understand what I want to achieve) and the other with some additions that come closer to the solution. Please correct my second version and/or point me to specific documentation. (I have general documentation of Java generics. But my code seems to have several interfering challenges and it is hard to a correct solution)
About my example: There is an abstract base type and several implementing variants (only one is given). Method combine() calls getOp1(), which decides (depending on <some condition>) if it should operate on its own instance or on a new one. After the calculation, it returns the target instance.
abstract class Base {
protected final Base getOp1() {
if(Util.isConditionMet()) { return getNewInstance(); }
else { return this; }
}
protected abstract Base getNewInstance(); // returns a new instance of an implementing class
public abstract Base combine(Base other);
}
class Variant extends Base {
public Variant getNewInstance() { return new Variant(); }
public combine(Variant op2) {
Variant op1 = getOp1();
op1.calculate(op2);
return op1;
}
private void calculate(Variant other) { /* some code */ }
}
The version with some generics added. This version is faulty and does not compile.
abstract class Base<T extends Base<T>> {
protected final T getOp1() {
if(Util.isConditionMet()) { return getNewInstance(); }
else { return this; }
}
protected abstract T getNewInstance(); // returns a new instance of an implementing class
public abstract T combine(T other);
}
class Variant<T extends Variant<T>> extends Base<T> {
protected T getNewInstance() { return new Variant(); }
public T combine(T op2) {
T op1 = getOp1();
op1.calculate(op2);
return op1;
}
private void calculate(T other) { /* some code */ }
}
To make this code working, you need to resolve incompatibility type issues: replace T returning types by Base<T> and cast result of Variant#getOp1() to Variant<T> to allow invoke calculate() on it (this is safe here because Variant#getOp1() always returns Variant:
abstract class Base<T extends Base<T>> {
protected final Base<T> getOp1() {
return condition() ? getNewInstance() : this;
}
protected abstract Base<T> getNewInstance();
public abstract Base<T> combine(T other);
}
class Variant<T extends Variant<T>> extends Base<T> {
protected Base<T> getNewInstance() {
return new Variant();
}
public Base<T> combine(T op2) {
Variant<T> op1 = (Variant<T>) getOp1(); // <- explicit cast
op1.calculate(op2);
return op1;
}
private void calculate(Base<T> other) {
// ...
}
}
Btw, I still see no reason of such complicated type structure.
I have seen a couple of such combinational, operational classes, though never too elaborate. Maybe inheritance is not the right tool.
Better to use a lookup mechanism for capabilities, features.
class Base {
// Untyped
private Map<Class<?>, Object> capabilities = new HashMap<>();
protected <I> void register(Class<I> intf, I obj) {
capabilities.put(intf, obj);
}
public <T> Optional<T> lookup(Class<T> intf) {
Object obj = capabilities.get(intf);
return obj == null ? Optional.emtpy() : Optional.of(intf.cast(obj));
}
}
interface Flying {
void fly(double altitude);
}
Base pelican = new Pelican();
Flying flying = pelical.lookup(Flying.class).orElse(null);
flying.fly(0.5);
This also allows dynamic changes, and combining things with respect to two aspects.
Legacy code:
public <B extends IBox> List<B> getBoxList(String key)
There is no way for the method to know which subtype the caller is actually expecting, so there is no sensible way to fulfill this contract.
Important: there is no way to infer the expected subtype from the key.
Therefore the signature should be:
public List<IBox> getBoxList(String key)
Is my reasoning correct?
You can easily do that like this:
public List<? extends IBox> getBoxList(String key)
No, it doesn't. Consider the following code which won't even compile under Java 8, but will compile under Java 7 with a warning. The caller is actually expecting a list of BlueBox from the BoxDB:
List<BlueBox> boxList = boxDB.<BlueBox>getBoxList("123");
But what he actually gets is a List of RedBox. So the method is not delivering what it promises.
import java.util.*;
public class HelloWorld
{
public static void main(String[] args)
{
BoxDB boxDB = new BoxDB();
List<BlueBox> boxList = boxDB.<BlueBox>getBoxList("123");
for (IBox box: boxList) {
System.out.println(box.getClass().getName());//prints "RedBox"
}
}
}
interface IBox {
String getKey();
}
class RedBox implements IBox {
String key;
public RedBox(String key) {
this.key = key;
}
public String getKey() {
return key;
}
}
class BlueBox implements IBox {
String key;
public BlueBox(String key) {
this.key = key;
}
public String getKey() {
return key;
}
}
class BoxDB
{
public <B extends IBox> List<B> getBoxList(String key) {
List<B> result = new ArrayList<>();
result.add((B)new RedBox("123"));
return result;
}
}
There is a subtle difference between the two. The first retains the type while the second flattens the type to it's interface. By moving to the second you are essentially discarding some information that may be useful to the caller.
interface IBox {
}
public static <B extends IBox> List<B> getBoxList1(String key) {
return null;
}
public static List<IBox> getBoxList2(String key) {
return null;
}
class ABox implements IBox {
}
class BBox implements IBox {
}
public void test() {
List<ABox> aBox = Test.<ABox>getBoxList1("Hello");
List<BBox> bBox = Test.<BBox>getBoxList1("Hello");
// Not allowed.
List<ABox> cBox = Test.getBoxList2("Hello");
List<IBox> dBox = Test.getBoxList2("Hello");
}
To explain this lets start with an example
public RedBox implements IBox{
//implementation here
}
public BlueBox implements IBox{
//implementation here
}
Now suppose one case I need list of RedBoxe and YellowBox then my call as per the first code would be
List<RedBox> redBoxList = getBoxList(redKey);
List<YellowBox> yellowBoxList = getBoxList(yellowKey);
But in the later case this would be:
List<RedBox> redBoxList = (List<RedBox>)getBoxList();//Since it returns List<IBox>
List<RedBox> redBoxList = (List<RedBox>)getBoxList();
So the former code is much efficient in ensuring type safety.
Former code makes more sense. To read more about generics refer to Effective Java.