为什么Scala编译器不能为未密封的类/特征给出模式匹配警告?


10

如果我使用密封的traitabstract class在Scala中使用模式匹配,我想知道,编译器是否不知道在编译时针对该特定模式匹配,可以使用此特性/类的哪些可能的实现?所以,如果这样做,会不给模式匹配的警告,即使是在trait/ abstract class不密封,因为他知道哪些类型可以被使用,通过检查所有可能的依赖性/进口?

例如,如果我有一个,Option[A]并且我只为Some[A]但不为进行模式匹配None,则编译器会抱怨,因为Option是密封的。

如果编译器无法知道/解决该问题,那为什么不呢?如果编译器(理论上)可以做到这一点,那么在Scala中不使用它的原因是什么?还有其他支持这种行为的语言吗?


不清楚您要问什么。如果match表达式不能覆盖所有可能的输入,您是否希望编译器发出警告?也许举个例子可以使您的问题更加清楚。
kdgregory 2014年

2
如果任何人都可以引入一个新的子类,则模式匹配永远不会是详尽无遗的。例如,您产生了一个Foo带有子类AB和的抽象类C,并且您所有的模式匹配项仅与这三个匹配。没有什么能阻止我添加一个新的子类D,它会破坏您的模式匹配。
Doval 2014年

@kdgregory是的,您知道了。我添加了一个示例以使其更加清晰。
valenterry 2014年

3
检查所有导入不足以发现所有可能的子类。另一个子类可以在单独的类文件中声明,然后在运行时通过加载java.lang.ClassLoader
阿蒙2014年

Answers:


17

找出一个类的所有子类称为“类层次分析”,用具有动态代码加载能力的语言执行静态CHA等效于解决“停止问题”。

另外,Scala的目标之一是分别编译和部署独立模块,因此,编译器根本无法知道一个类是否在另一个模块中被子类化,因为它从不看多个模块。(毕竟,您可以针对某个其他模块的接口来编译模块,而该模块甚至不存在于您的系统中!)这就是为什么sealed要求所有子类都在同一编译单元中定义的原因。

这也是JVM与C ++编译器竞争如此出色的原因之一:C ++编译器通常是静态编译器,因此它们通常无法确定方法是否被覆盖,因此无法内联。JVM OTOH通常是动态编译器,它们不需要执行CHA即可确定某个方法是否被覆盖,它们可以在运行时查看类层次结构。即使在程序执行的后期,出现了一个以前没有的新子类,也没什么大不了的,只是重新编译那段代码而不用内联。

注意:所有这些仅适用于Scala。JVM没有的概念sealed,因此完全有可能sealed另一种 JVM语言子类化类,因为无法将其传达给另一种语言。该sealed属性记录在ScalaSig注释中,但是其他语言的编译器显然不会考虑这些注释。


3

可以做(至少在编译时已知的所有类),它只是昂贵。您将完全破坏增量编译,因为每次更改任何其他文件时,都必须重新编译包含模式匹配项的所有内容。

你要买什么?编写模式匹配是一种代码气味,当添加新的派生类时,该模式匹配需要经常更改。这违反了开放/封闭原则。正确使用继承,您将无需编写这些模式匹配。是的,开放/关闭原则也适用于没有基于类的继承的功能语言。实际上,在类型类,多方法以及仅是普通的高阶函数之类的功能之间,功能语言使无需修改的扩展变得更加容易。


1
It can be done (at least for all classes known at compile time), it's just expensive.但是,如果程序不是100%独立的(即,它取决于外部.jar文件),那么在通过s 之一进行编译,您是否可以潜入新的子类中jar?因此,编译器可能会告诉您“您的模式匹配现在已经很详尽,但是如果您的任何依赖项发生更改,它都可能会改变”,这是毫无用处的,因为拥有外部依赖项的目的是能够在不重新编译的情况下对其进行更新!
Doval 2014年

因此,免责声明。在实践中,如果紧密耦合在一起,需要对依赖项(外部或其他)进行详尽的匹配,则无论如何都需要重新编译。
Karl Bielefeldt 2014年

@Doval然后,您应该使用某种形式的委托,并让被调用的类决定做什么并反转控制。这就是OOP的目的。如果您不希望那样,那么您会遇到当前问题。
雪橇2014年

@ArtB我看不到与此相关的委托或控制反转。
Doval 2014年

如果您希望它与能够在外部添加它的人一起工作,请调用该类并将逻辑移到那些类中。
雪橇2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.