Skip to content

Instantly share code, notes, and snippets.

@ctrueden
Created August 31, 2018 15:44
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 ctrueden/1a6e1421fb22af0e31bf08ba310cfc68 to your computer and use it in GitHub Desktop.
Save ctrueden/1a6e1421fb22af0e31bf08ba310cfc68 to your computer and use it in GitHub Desktop.
Some characteristics of generics, assignability, satisfiability, recursive and otherwise.
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
import net.imglib2.img.Img;
import net.imglib2.img.array.ArrayImgs;
import net.imglib2.type.numeric.RealType;
import net.imglib2.type.numeric.real.DoubleType;
public class RecursiveGenericsChallenges {
public static <I extends Number, O> void go() {
Function<I, O> thing = null;
Function<Double, Double> dThing = null;
thing = dThing; // iff this compiles, then Types.isAssignable(new Nil<Function<Double, Double>>(){}.getType(), new Nil<Function<I, O>>(){}.getType()); is true.
dThing = thing; // iff this compiles, then Types.isAssignable(new Nil<Function<I, O>>(){}.getType(), new Nil<Function<Double, Double>>(){}.getType()); is true.
// NEITHER OF THESE COMPILE
// OK, SO WHEN exactly can some ParameterizedType assignments actually work?
Function<Double, Double> otherDThing = dThing;
Function<?, ?> wildcardThing = dThing; // OK
Function<?, ?> wildcardThing2 = thing; // OK
Function<? extends Number, ?> wildcardNumberThing = thing; // OK
Function<? extends Number, ?> wildcardNumberThing2 = dThing; // OK
// The thing that makes this so constrained is: generics are not covariant.
List<Number> nList = new ArrayList<>();
Integer five = 5;
nList.add(five);
Number firstNumber = nList.get(0);
List<Integer> ints = new ArrayList<>();
nList = ints; // BAD
List<? extends Number> someKindOfNumbers = ints; // OK
someKindOfNumbers.add(someKindOfNumbers.get(0)); // Somewhat interestingly: FAIL
((List) someKindOfNumbers).add(someKindOfNumbers.get(0)); // Going throw a raw types works, but is NOT type safe
// Better: bind the list's parameter via a method call.
addFirstElementAgain(someKindOfNumbers);
// BUT: You cannot "escape from" wildcards if the type parameters are recursive :-(
// This is because the two ?s are not the same thing.
Img<? extends RealType<?>> mysteryImage = null;
doAwesomeThingToImage(mysteryImage);
// This works, but not type safe:
Img<? extends RealType> mysteryImage2 = null;
doAwesomeThingToImage(mysteryImage2);
// This works, but REALLY not type safe:
Img<? extends RealType<?>> mysteryImage3 = null;
doAwesomeThingToImage((Img) mysteryImage3);
// This works, but causes difficulties too.
Img<RealType<?>> mysteryImage4 = null;
doAwesomeThingToImage(mysteryImage4);
Img<DoubleType> myDoubleImage = ArrayImgs.doubles(5, 5);
mysteryImage4 = myDoubleImage; // NOPE
Img<RealType<?>> anotherMystery = myDoubleImage; // NOPE
}
private static <N extends Number> void addFirstElementAgain(List<N> myNumberList) {
myNumberList.add(myNumberList.get(0)); // YAY
}
private static <T extends RealType<T>> void doAwesomeThingToImage(
Img<T> mysteryImage)
{
mysteryImage.cursor().next().setReal(100.0);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment