英文:
Couldn't understand why Java and Scala lower bounds behave different
问题
I've very simple example both in java and scala
Java one:
public class LowerBound {
public void myFunction(List<? super Integer> myList) {
myList.forEach(System.out::println);
}
}
public class LowerBoundMain {
public static void main(String[] args) {
LowerBound lb = new LowerBound();
List<Integer> myList1 = new ArrayList<Integer>();
myList1.add(1);
myList1.add(2);
myList1.add(3);
lb.myFunction(myList1);
List<Double> myList2 = new ArrayList<Double>();
myList2.add(2.0);
myList2.add(3.2);
//lb.myFunction(myList2);
}
}
here as I expected lb.myFunction(myList2) gives an error because I'm waiting List<Integer> or supertype of List<Integer>, and List<Double> is not a supertype of Integer
But in Scala
class AnotherLowerBound {
def myFunction[T >: List[Int]](input: T) = {
println(input)
}
}
object LowerBoundScalaMain extends App{
val pos1 = new AnotherLowerBound
val myList: List[Double] = List(2.32,4.31,3.54)
pos1.myFunction(myList)
}
it prints List[Double] without problem?
Is the reason in Scala both List[Double] and List[Integer] are a subtype of AnyRef? Or am I doing some syntax mistake?
英文:
I've very simple example both in java and scala
Java one:
public class LowerBound {
public void myFunction(List<? super Integer> myList) {
myList.forEach(System.out::println);
}
}
public class LowerBoundMain {
public static void main(String[] args) {
LowerBound lb = new LowerBound();
List<Integer> myList1 = new ArrayList<Integer>();
myList1.add(1);
myList1.add(2);
myList1.add(3);
lb.myFunction(myList1);
List<Double> myList2 = new ArrayList<Double>();
myList2.add(2.0);
myList2.add(3.2);
//lb.myFunction(myList2);
}
}
here as I expected lb.myFunction(myList2) gives an error because I'm waiting List<Integer> or supertype of List<Integer>, and List<Double> is not a supertype of Integer
But in Scala
class AnotherLowerBound {
def myFunction[T >: List[Int]](input: T) = {
println(input)
}
}
object LowerBoundScalaMain extends App{
val pos1 = new AnotherLowerBound
val myList: List[Double] = List(2.32,4.31,3.54)
pos1.myFunction(myList)
}
it prints List[Double] without problem?
Is the reason in Scala both List[Double] and List[Integer] are a subtype of AnyRef? Or am I doing some syntax mistake?
答案1
得分: 5
-
Scala和Java拥有不同的类型系统,它们不必表现相同的方式。
-
在Java示例中,您使用了存在类型,而在Scala示例中,您使用了参数化类型,因此这已经是苹果与橙子的比较。您将不得不在Java中定义签名,如下所示:
<T super Integer> void myFunction(List<T> myList)
但是这不是有效的Java代码。
-
在Java中,除了数组(Array)之外的所有数据结构都是不变的,因此类型推断将无法找出两种不同类型的最小上界。在Scala中,不可变列表(Immutable Lists)是协变的,允许类型推断找到
List[Int]
和List[Double]
都是List[AnyVal]
类型。 -
List[AnyVal]
是对泛型Scala方法调用进行的类型推断。Java无法做到这一点(它不允许定义协变的类型参数),因此在编译时,当需要推断Java的可变List[Integer]
和List[Double]
的公共超类型以传递存在类型的值时,它会编译失败。
英文:
-
Scala and Java have different type systems, they don't have to behave the same way
-
in Java example you used existential type, in Scala example you used parametric type, so it's already apples vs oranges. You would have to define signature in Java as
<T super Integer> void myFunction(List<T> myList)
except that is not a valid Java code
-
All data structures (except Array) are invariant in Java, so type inference won't be able to figure out least upper bound of two different types. In Scala immutable Lists are covariant allowing type inference to find that
List[Int]
andList[Double]
are both of typeList[AnyVal]
-
List[AnyVal]
is the type inferred for the call of generic Scala method. Java is not able to do this (it doesn't allow defining type parameter to be covariant) so it fails for compile when it would have to infer a common supertype of Java's mutableList[Integer]
andList[Double]
to pass value as existential type.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论