35

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));
  }
}

)

Alex
  • 8,093
  • 6
  • 49
  • 79
Bastl
  • 2,926
  • 5
  • 27
  • 48
  • 10
    Unfortunately, attempting to use any good (whether haskell-ish or not) style in Java tends to result in verbose code, which is not good style, and therefore it is impossible. In all honesty, although it pains me, I'd probably just throw two exceptions as a hack... – alternative Apr 02 '12 at 12:34
  • Here's a similar question for anyone who wants more reading resources: http://stackoverflow.com/questions/12753880/adt-like-polymorphism-in-java-without-altering-class – Tarrasch Aug 04 '16 at 07:17
  • update: here is a solution for SUM types in general (Either is the genuine SUM type) by Philip Wadler, LambdaWorld 2016: https://www.youtube.com/watch?v=V10hzjgoklA&t=1742s – Dierk Sep 16 '17 at 21:12

14 Answers14

35

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
}
AdrieanKhisbe
  • 3,899
  • 8
  • 37
  • 45
newacct
  • 119,665
  • 29
  • 163
  • 224
  • even better :-) Short and concise. Everyone with a course on algebraic datatypes and basic java knowledge should understand this. Well-done! – Bastl Apr 05 '12 at 10:49
  • 6
    That's about the same approach as having `isLeft`, `getAsLeft` and `getAsRight` methods. It is not type safe (it relies on correct client code): You can have exceptions when casting if you mess it client-side. – ziggystar Apr 16 '12 at 08:56
  • If you're going to do an Either, you should use Disjunction (a right biased Either). That way, you use map and flatMap directly (it will execute the operation if Right, else do nothing. It is common to have an Exception on the left. This is the behavior in Scalaz. – jordan3 May 29 '14 at 00:12
  • 1
    This is the way I do sum types in OO languages, except (in the absence of proper pattern matching) I prefer the Visitor pattern to `instanceof` because it's more type-safe. I'm surprised none of the other answers have mentioned this. – Benjamin Hodgson Oct 20 '15 at 16:08
  • @BenjaminHodgson But my answer from 3 years ago, at least, implements the visitor pattern. Sorry that I do not know these funny names… – ziggystar Jul 08 '21 at 15:08
26

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).

ziggystar
  • 28,410
  • 9
  • 72
  • 124
  • so you bind the type by defining the function, right? It is just to trick the compiler and it could also be empty? – Bastl Apr 02 '12 at 12:40
  • and just for the records: The Either.left/right are the actual constructors in the algebraic sense? – Bastl Apr 02 '12 at 12:40
  • 3
    @Bastl `left`/`right` are the constructors. I'm no Haskell person and don't really understand what you meanwith "bind the type". The `Function` is just a Helper class (for first-class functions) and could be defined somewhere else. There's nothing that could be empty here. The trick is that `fold` only calls the correctly typed function. The calling code always has to provide handling functions for `A` and `B`. – ziggystar Apr 02 '12 at 12:44
  • Note that in FunctionalJava the data is stored in one of two inner classes "Left" or "Right" which only have the corresponding private field. The example above always has both fields with (at least) one of them null. (But this is not enforced by the constructor above!) – Chris Kuklewicz Apr 03 '12 at 10:59
  • 1
    @ChrisKuklewicz Well, it is. The constructor is private and the factory methods enforce this. – ziggystar Apr 03 '12 at 11:03
  • 2
    In terms of Haskell, what you're doing here is exploiting the isomorphism `(∀ r . (a -> r) -> r)` ≅ `a` so that `Either a b` ≅ `(∀ r . (Either a b -> r) -> r)` ≅ `(∀ r . (a -> r, b -> r) -> r)`. – leftaroundabout Oct 20 '15 at 12:55
9

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.

Riccardo T.
  • 8,907
  • 5
  • 38
  • 78
  • 2
    Make `Either` abstract and declare `L getLeft()` and `R getRight()` and `bool isRight()`. Now, make `LeftEither` and `RightEither` with correct constructors to avoid the type erasure collision between the two constructors. [Darn you, type erasure!] – alternative Apr 02 '12 at 12:22
  • @alternative: thanks for specifying, I didn't think about type erasure. – Riccardo T. Apr 02 '12 at 14:20
  • 1
    Alternatively, one could specify two constructors `Either(L left, Void right)` and `Either(Void left, R right)`. Since `Void` is uninstantiable, one of the two arguments must always be `null`, resolving the ambiguity (although the actual value wrapped by Either can now not be null itself, but this could also be considered a feature and not a bug). – arne.b Apr 03 '12 at 07:15
7

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.

gpampara
  • 11,989
  • 3
  • 27
  • 26
  • 1
    The encoding in FunctionalJava is the most accurate of these answers (when I wrote this comment at least). Also see the longer example at http://blog.tmorris.net/understanding-practical-api-design-static-typing-and-functional-programming/ for more inspiration about sum types in Java. – Chris Kuklewicz Apr 02 '12 at 12:40
  • @ChrisKuklewicz Thanks for the link - I couldn't find it at the time :) – gpampara Apr 02 '12 at 12:51
  • 1
    404. New link:http://blog.tmorris.net/posts/understanding-practical-api-design-static-typing-and-functional-programming/ – Philip Durbin Feb 26 '14 at 13:26
4

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.)

Tom Hawtin - tackline
  • 145,806
  • 30
  • 211
  • 305
  • Many would argue that the inversion of control you propose makes for more obtuse code. But less subjectively, Java imposes major performance penalty: no tail call optimization. Consider, chaining together a bunch of functions that take/return an Either uses constant stack space. With the visitor pattern, whether you pass in a stack of handlers or even hard code in specific handlers, you use O(number of handlers) stack space. TL;DR: visitor pattern unnecessarily denigrates space efficiency in Java. – Ericson2314 Dec 07 '13 at 22:28
4

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.

3

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.

Ericson2314
  • 133
  • 7
2

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.

JbGi
  • 197
  • 6
2

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>
Dominic Fox
  • 1,039
  • 11
  • 8
2

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

Community
  • 1
  • 1
Nikita Volkov
  • 42,792
  • 11
  • 94
  • 169
1

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.

Dylan
  • 13,645
  • 3
  • 40
  • 67
  • Just tagged to get attention from ppl knowing both sides of the world. ;-) – Bastl Apr 02 '12 at 12:20
  • One thing that i really like in either is that you can write your signature as `def foo(bar: Boolean) : Int Either String = ...`. I think it is closer to the meaning behind Either. – om-nom-nom Apr 02 '12 at 13:00
0

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();
}
Community
  • 1
  • 1
Usman Saleem
  • 1,665
  • 9
  • 18
0

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);
    }   
}
millimoose
  • 39,073
  • 9
  • 82
  • 134
  • @Bastl The boolean is hidden by the `newLeft` and `newRight` methods - it's an implementation detail. I chose to pass the class to the factory methods so I can use what little type inference Java has. The alternative would be using explicit generic parameters to the method call, which is uglier. – millimoose Apr 02 '12 at 12:08
  • 1
    @Bastl If you want this done "nicely", use Haskell. You're asking for a feature which is a terrible fit for Java, any straightforward implementation will thus look terrible. – millimoose Apr 02 '12 at 12:08
-8

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.

Michael Borgwardt
  • 342,105
  • 78
  • 482
  • 720
  • 3
    But it is much more powerful that using exceptions. This feature is called algebraic / disjoint sum, I don't think it is absurd.... – Bastl Apr 02 '12 at 11:59
  • 1
    @Bastl Remember that Java has OO. If you need to return two different data types from a method, you can usually return their common supertype, and have polymorphism handle the different behaviour for each variant. – millimoose Apr 02 '12 at 12:04
  • 1
    Inheritance is a dangerous thing. The consequence is to return "Object" in my initial example, and type-safety is gone ... – Bastl Apr 02 '12 at 12:07
  • @Bastl A workaround would be creating such as `StringHolder` and `IntegerHolder` that extend `ValueHolder` which defines the polymorphic behaviour. That said I find it hard to imagine an actual use case for having a method return one of two completely unrelated basic types. – millimoose Apr 02 '12 at 12:14
  • @Bastl: so it's more pwerful in theory, but nobody seems to have found it useful for anything other than exceptions. Same thing. If you like to explore type systems for their conceptual beauty rather than practicall usefulness, I suspect you'll never be happy with Java... – Michael Borgwardt Apr 02 '12 at 12:16
  • Inerdial: yes. I understand your approach, but that's kind of re-implementing parts of Haskell type-inference in Java executed at runtime. – Bastl Apr 02 '12 at 12:19
  • @Michael Borgwardt Its not that its more useful for exceptions, its that it is common to define Either-like data types for better style. For example, a list could be defined as "`List a = Either (a, List a]) ()` [Although more likely you would use `Maybe` for this case] but it is typically chosen instead to use the more clear `List a = Item a (List a) | Empty` – alternative Apr 02 '12 at 12:25
  • @MichaelBorgwardt practical use case: SQL parser that accepts duplicates in result column names; but must reject selecting such ambiguous column from a subquery, for example `SELECT * FROM points p1 JOIN points p2 ON sqr(p1.x-p2.x)+sqr(p1.y-p2.y) < 100` is fine, `SELECT x,y FROM (...) AS pointPairs` is not. An implementation could map column names into `Either`. – Adrian Panasiuk Apr 17 '13 at 19:11
  • The problem with exceptions comes in Java 8 when you have lambdas: 1. You can use checked exceptions, but then you cannot use lambdas 2. You can use unchecked exceptions, but then you do not know what exceptions may occur – whirlwin Feb 17 '15 at 09:58