揭开斯卡拉神话

什么是最常见的关于斯卡拉语言的误解,以及这些反例如何存在?

UPDATE

我正在考虑更多关于我见过的各种声明,比如“Scala是dynamictypes的”和“Scala是一种脚本语言”。

我接受“斯卡拉(简单/复杂)”可能被认为是一个神话,但它也是一个非常依赖于上下文的观点。 我个人的看法是,这些function可以让Scala显得简单或复杂,这取决于谁在使用它们。 最终,语言只是提供抽象,而这正是用这些方式来形成感知的方式。

不仅如此,它还有一定的激化论点的倾向,我还没有看到任何人改变对这个话题的强烈的观点。

误解:Scala支持运算符重载。

实际上,Scala方法调用的方法命名规则和中缀语法是非常灵活的,在用“运算符”使用中缀语法时,具有确定方法优先级的特殊规则。 这个微妙的区别对于滥用这种语言function的效用和潜在的重要意义,与真正的运算符重载(la C ++)相比,正如詹姆斯·伊里(James Iry)对这个问题的回答中所解释的那样。

误解: Scala的“Option”和Haskell的“Maybe”types不能让你从null中解救出来 。 🙂

Debunked: 为什么Scala的“Option”和Haskell的“Maybe”types可以让你免于被James Iry所忽略。

我不同意Scala很难的观点,因为你可以使用非常先进的function来完成这些function。 Scala的可伸缩性意味着您可以在Scala中编写DSL抽象和高级API,否则需要语言扩展。 所以公平地说,你需要将Scala库与其他语言编译器进行比较。 人们并不认为C#很难,因为(我认为,对此没有掌握第一手知识),C#编译器是相当难以理解的。 对于斯卡拉来说,这一切都是公开的。 但是我们需要明确一点,大多数人不需要在这个层面编写代码,他们也不应该这样做。

我认为在许多Scala开发者中,EPFL(和你自己,Kevin)的普遍的误解是, “scala是一种简单的语言” 。 争论通常是这样的:

  • 斯卡拉有几个关键字
  • Scala重用相同的几个构造 (例如, PartialFunction语法被用作catch块的主体)
  • 斯卡拉有几个简单的规则 ,允许您创build库代码(可能看起来好像语言有特殊的关键字/结构)。 我在这里想的是implicits; 包含冒号的方法; 允许的标识符号; X(a, b)a X b与提取器的等价性。 等等
  • 斯卡拉的声明网站的变化意味着types系统只是你的方式。 没有更多的通配符和? super T ? super T

我个人的看法是这个说法完全是彻底的假 。 斯卡拉的types系统与implicits一起使用,可以为普通开发人员写出坦率的不可思议的代码 。 不pipe上面的“指标”是什么让你思考,任何build议都是荒谬的。 ( 请注意,那些我在Twitter和其他地方嘲笑过Java的非复杂性的人,恰巧是超级聪明的types,他们有时看起来在元素,函子和箭头的掌握之前,裤子 )。

明显的反对意见是(当然):

  1. 你不必写这样的代码
  2. 你不必迎合普通的开发者

其中,在我看来,只有#2是有效的。 不pipe你写的代码是否和scalaz一样复杂,我认为使用这种语言(并继续使用它),而对types系统没有真正的理解是愚蠢的。 如何才能从语言中得到最好的结果?

神话:方法和function是一回事。

实际上,一个函数是一个值( FunctionN类之一的一个实例),而一个方法则不是。 Jim McBeath更详细地解释了这些差异 。 最重要的实际区别是:

  • 只有方法可以有types参数
  • 只有方法可以采取隐式的参数
  • 只有方法可以有命名和默认参数
  • 当引用一个方法时,通常需要用下划线来区分方法调用和部分函数应用程序(例如, str.length计算结果为一个数字,而str.length _计算结果为零参数函数)。

有一个神话,斯卡拉是困难的,因为斯卡拉是一个复杂的语言。

这是错误的 – 通过各种指标,Scala并不比Java复杂。 (语法的大小,代码行数或类的数量或标准API中的方法的数量等)。

但毫无疑问,Scala代码可能难以理解。 如果Scala不是一个复杂的语言,怎么会这样呢?

答案是,斯卡拉是一个强大的语言。 与Java有许多特殊的构造(比如枚举)完成一件特定的事情 – 并且要求你学习仅仅适用于这一件事的专用语法,Scala有许多非常一般的构造。 通过混合和匹配这些结构,可以用很less的代码来expression非常复杂的想法。 而且,毫不奇怪的是,如果有人出现并没有相同的复杂想法,并试图弄清楚你在用这个非常简洁的代码做什么,他们可能会觉得这是令人生畏的 – 甚至比看到一对夫妇更令人生畏的代码页做同样的事情,从那时起,至less他们会意识到有多less概念的东西要了解!

还有一个问题是否事情比他们真正需要的更为复杂。 例如,collections品库中存在的一些types的体操使得collections品使用但令人费解的实施或扩展是令人愉快的。 这里的目标并不特别复杂(例如,子类应该返回自己的types),但是所需的方法 (高级types,隐式构build者等)是复杂的。 (事实上​​,这样的复杂性实际上是Java放弃了而不是尝试,而不是像在Scala中那样“恰当”地执行它。另外,原则上希望这个方法在将来可以改进,因为这个方法可以进化以更接近地匹配目标)。在其他情况下, 目标是复杂的; list.filter(_<5).sorted.grouped(10).flatMap(_.tail.headOption)有点乱,但是如果你真的想把所有小于5的数字,然后把每个第二个数字在剩下的列表中有10个,这只是一个有点复杂的想法,而且代码几乎说明了如果你知道基本的集合操作的话。

总结:Scala并不复杂,但它可以让你简洁地expression复杂的想法。 对复杂想法的紧凑expression可能令人望而生畏。


Scala是一个不可部署的神话,而广泛的第三方Java库可以毫不费力地部署。

就这个神话的存在而言,我怀疑它存在于不习惯将虚拟机和API从语言和编译器中分离出来的人群中。 如果你的头脑中有java == javac == Java API,如果有人build议使用scalac而不是javac,那么你可能会感到有点紧张,因为你看到了你的JVM运行的很好。

斯卡拉最终成为JVM字节码,加上自己的自定义库。 没有理由再担心小规模部署Scala或作为其他大型项目的一部分,因为部署任何其他库可能会或可能不会与您喜欢的任何JVM兼容。 诚然,Scala开发团队的支持力度不及Google的collections版或Apache Commons,但它至less像Java Advanced Imaging项目一样重要。

与演员图书馆有关的一些常见的误解:

  • 参与者处理并行传入的消息,在多个线程/针对线程池(事实上,处理multithreading中的消息是违背行为者的概念,并可能导致竞争条件 – 所有消息在一个线程中被顺序处理(基于线程参与者使用一个线程进行邮箱处理和执行;基于事件的参与者可以共享一个VM线程执行,使用multithreading执行程序来调度邮箱处理))
  • 未捕获的exception不会改变参与者的行为/状态(实际上,所有未捕获的exception终止参与者)

神话:

 def foo() = "something" 

 def bar = "something" 

是一样的。

不是这样; 你可以调用foo() ,但是bar()试图调用StringLike的apply方法而没有参数(导致错误)。

误解:当从零开始计算某个总和时,可以使用减less来replace折叠。

这是Scala新用户常见的错误/误解,特别是那些没有function编程经验的用户。 以下expression式不是等同的:

 seq.foldLeft(0)(_+_) seq.reduceLeft(_+_) 

这两个expression式在处理空序列时有所不同:fold产生一个有效的结果(0),而reduce引发一个exception。

神话: 模式匹配不适合OO范式 。

Martin Odersky本人在这里揭穿 (另请参阅本文 – 使用模式匹配对象 – Odersky等人)

误解: this.type引用this.type表示的相同types。

作为这种误解的一个例子,可以假定在下面的代码中, v.me的types是B

 trait A { val me: this.type = this } class B extends A val v = new B 

实际上, this.type是指只有其实例的types。 通常, x.type是唯一实例是x的单例types。 所以在上面的例子中, v.me的types是v.type 。 下面的会议表明了原则:

 scala> val s = "a string" s: java.lang.String = a string scala> var v: s.type = s v: s.type = a string scala> v = "another string" <console>:7: error: type mismatch; found : java.lang.String("another string") required: s.type v = "another string" 

Scala具有types推断和改进types(结构types),而Java没有。

这个神话是由詹姆斯·伊里(James Iry) 破坏的。

神话:Scala具有高度的可扩展性,没有限定什么forms的可扩展性。

就expression高级指示语义的能力而言,Scala的确具有高度的可扩展性,这使得它成为一种非常好的语言,用于实验,甚至可以在自上而下的协调组合的项目级扩展生产。

然而,每一种不透明的语言(即允许可变的数据结构)都是必要的(而不是声明性的),并且不会扩展到自下而上的 WAN ,不协调的组合性和安全性。 换句话说,命令式语言是组合(和安全)意大利面条,而不协调的模块开发。 我认识到,这种不协调的发展可能是目前大多数人认为的“pipe道梦”,因此可能不是一个高度优先的事情。 这不是为了贬低高层次语义统一可以提供的组合性(即消除angular落案例)的好处,例如标准库的类别理论模型 。

对于许多读者来说,可能存在显着的认知失调,并且在充分理解我提出的问题之前,他们可能过早地按下“下调”的投票,特别是因为关于命令与声明(即可变与不可变) ,( 渴望与懒惰 ),例如,一元语义从来就不是固有的必要条件, 但它却是一种谎言 。 是的,在Haskell IO monad是必不可less的,但它是必要的没有任何与它是一个单子。

我在“Copute Tutorial”和“Purity”部分对此进行了更详细的解释,这些部分可以在主页上,也可以暂时在这个链接上 。

我的观点是我非常感谢Scala的存在,但我想澄清一下Scala的规模,什么不是。 我需要Scala的function,也就是说,对我来说,这是创build新的声明性语言的理想平台,但是Scala本身并不是唯一的声明性的,而且afaik参考透明性不能由Scala编译器强制执行,除了记住使用val无处不在。

我认为我的观点适用于关于Scala的复杂性辩论。 我发现(到目前为止,大部分概念上,由于迄今为止我的新语言的实际经验有限),去除了可变性和循环,同时保留了菱形多重inheritance的子types(Haskell没有),从根本上简化了语言。 例如, Unit小说消失了,其他一些问题和build构就不必要了,例如非范畴理论标准库,理解等。