Skip to content

Instantly share code, notes, and snippets.

@jedws
Last active December 19, 2015 17:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jedws/5993596 to your computer and use it in GitHub Desktop.
Save jedws/5993596 to your computer and use it in GitHub Desktop.
Optional.flatMap must declare the output type of the supplied function to be covariant
package com.atlassian.variance.test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.notNullValue;
import org.junit.Test;
import com.google.common.base.Function;
final class Optional<A> {
private final A a;
Optional(A a) {
this.a = a;
}
<B> Optional<B> map(Function<A, B> f) {
if (a != null)
return new Optional<B>(f.apply(a));
return new Optional<B>(null);
}
<B> Optional<B> flatMapInvariant(Function<A, Optional<? extends B>> f) {
return flatMap(f);
}
<B> Optional<B> flatMap(Function<A, ? extends Optional<? extends B>> f) {
if (a != null) {
@SuppressWarnings("unchecked")
Optional<B> result = (Optional<B>) (f.apply(a));
return result;
}
return new Optional<B>(null);
}
A get() {
return a;
}
}
class OptionalTest {
class Parent {};
class Child extends Parent {};
@Test public void covariantReturn() {
Optional<Parent> some = new Optional<Parent>(new Parent());
Function<Parent, Optional<Child>> f = new Function<Parent, Optional<Child>>() {
@Override public Optional<Child> apply(Parent p) {
return new Optional<Child>(new Child());
}
};
Optional<Parent> mapped = some.<Parent> flatMap(f);
// does not compile
// Optional<Parent> mappedInvariant = some.<Parent> flatMapInvariant(f);
assertThat(mapped.get(), notNullValue());
}
}
package com.atlassian.variance.test;
class VarianceTest {
final class Box<A> {
final A a;
Box(A a) {
this.a = a;
}
A get() {
return a;
}
}
class Parent {}
class Child extends Parent {}
<A> A invariant(Box<Box<A>> box) {
return box.get().get();
}
<A> A covariantParam(Box<Box<? extends A>> box) {
return box.get().get();
}
<A> A covariantBox(Box<? extends Box<A>> box) {
return box.get().get();
}
<A> A covariantBoxAndParam(Box<? extends Box<? extends A>> box) {
return box.get().get();
}
void test() {
Box<Box<Parent>> pb = new Box<Box<Parent>>(new Box<Parent>(new Parent()));
Box<Box<Child>> cb = new Box<Box<Child>>(new Box<Child>(new Child()));
{
Parent p = invariant(pb);
Parent c = invariant(cb);
}
{
// doesn't compile:
//Parent p = covariantParam(pb);
//Parent c = covariantParam(cb);
}
{
Parent p = covariantBox(pb);
Parent c = covariantBox(cb);
}
{
Parent p = covariantBoxAndParam(pb);
Parent c = covariantBoxAndParam(cb);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment