In this answer it says...
// Universal types let you write things like:
def combine[T](source: List[T], dest: List[T]): List[T] = {
source ++ dest
}
But I did not understand the explanation.
Can someone explain the difference between the universal type example above and some of the similar examples (which contain existential types) below?
def combine2[_](source: List[_], dest: List[_]): List[_] = {
source ++ dest
}
def combine3(source: List[_], dest: List[_]): List[_] = {
source ++ dest
}
def combine4[A, B](source: List[A], dest: List[B]): List[_] = {
source ++ dest
}
def combine5[T](source: List[T], dest: List[T] forSome {type T}): List[T] forSome {type T} = {
source ++ dest
}
Java for good measure...
public static List<?> combine6(final List<?> source, final List<?> dest) {
return source;
}
// Why doesn't this compile?
public static <T> List<T> combine7(final List<?> source, final List<?> dest) {
return source;
}
Also, if I provide typetags, does that in any way replace the need for existential types?
def combineTypetag[A, B, C](source: List[A], dest: List[B])
(implicit tagA: TypeTag[A], tagB: TypeTag[B], tagC: TypeTag[C]): List[C] = {
source ++ dest
}