Scala 的语言设计有哪些缺陷?

关注者
620
被浏览
80,545
登录后你可以
不限量看优质回答私信答主深度交流精彩内容一键收藏

谢邀。

这个问题挺难回答的,因为功力不够;对编程语言认识广度和深度上都不够。

并且程序语言的设计又是个哲学和审美的问题,一千个人有一千个哈姆雷特,从来就没有一门完美的语言。所以仅从个人的喜好来回答几点。

1)类型系统是把双刃剑

我在blog里写过很多偏有关scala类型系统的,因为这部分是我学习scala过程中耗费最多精力去了解的。我非常理解为什么Jetbrains为什么要设计一门 kotlin 语言,他们的理由是scala很好很强大,但也有些过了,所以我们采取了折中的设计,借鉴scala但去掉它非常复杂的地方(主要是类型系统)。

要从设计上来证明它的不好之处,不太容易,有些不好的点,并不一定是设计层面的,而是实现层面的问题,比如类型推导为何不是用全局式的HM推导,而采用局部的基于流的推导;导致有些情况下不如haskell的推导那么强大。另外还有一些看上去奇奇怪怪的符号,也可以说是实现风格的问题。

对于设计上的争论,这里有一个例子,

scala雾中风景(15): class A { type T }与class A[T] {}

你会觉得这两种是否等价,或者那种更好?既然scala这么追求统一和一致性,为何在类型上不用一种方式呢?看看martin自己的解释:

https://github.com/wecite/papers/blob/master/An-Overview-of-the-Scala-Programming-Language/5.Abstraction.md#53–%E7%94%A8%E6%8A%BD%E8%B1%A1%E7%B1%BB%E5%9E%8B%E5%BB%BA%E7%AB%8B%E6%B3%9B%E5%9E%8B%E6%A8%A1%E5%9E%8Bmodeling-generics-with-abstract-types

>两种抽象模式之间可以转换,对于一种语言还是有价值的,因为可以降低其内在的概念复杂性。例如,Scala 的泛型,实际上就是一种语法糖,完全可以被抽象类型替代掉。既然如此,也许会有人问,这种语法糖有没有必要性?或者说为什么不只用抽象类型呢,这样可以使语法本身简化很多。实际上,Scala 中引入泛型有两重意义:首先,手工把泛型转化为成为抽象类型表达形式并不那么简单,不仅会丧失语法的简洁性,而且还可能带来前述的命名冲突等问题。其次,泛型和抽象类型在 Scala 中一般扮演不同的角色,泛型一般用于类型的实例化,而抽象类型主要用于在调用者代码中对相应的抽象类型进行引用。后者主要来自于两个场合:一个是有人需要在客户代码中隐藏相关类型信息,用于构造类似于SML模式的模块系统。另一个是在子类中协变地继承父类的类型,从而获得族多态。

>可能有人会问,那么是否可以反过来用泛型来替代抽象类型呢?一些对于两种抽象方式都支持的系统进行的研究 [27] 证实,这样做要困难得多,至少整个程序都需要重写。不仅如此,如果系统要实现受限多态的话,重写类型上/下界的部分会呈平方级增长 [8]。实际上这一点也不奇怪,因为这两种类型体系的理论基础就不同,泛型(不带 F-界的)可以用 F<: 系统来表达 [11],而抽象类型则建立在类型依赖的基础之上。后者比前者的表现力更强,例如,带路径依赖类型的 νObj 演算是可以涵盖 F<: 的。


2)灵活性也是把双刃剑(eg: 操作符重载)

我个人不排斥这个特性,但团队协作上需要克制。当年有段采访Java之父Gosling在回答为何不支持无符号类型(unsigned int)时,说非常多的语言都是因为它们太过灵活而死亡的,所以他要尽可能保持简单。现在来看,是一种大智若愚的做法。

3) Martin的野心太大

即想支持脚本式开发,又想担当系统语言;即想要动态语言的灵活性,又想要静态语言的安全性;即想运行在JVM上,又想运行在.NET上;总之是想得非常宏大,实际能力却不匹配(背后没有大财团支持),在实现上有很多bug(编译器和类库),还有兼容性的问题,都给用户一种不够可靠的感觉(相对于java)。