揭穿斯卡拉神话

Kev*_*ght 58 programming-languages scala

关于Scala语言最常见的误解是什么,以及这些例子中存在哪些反例?

UPDATE

我正在考虑更多关于我见过的各种声明,例如"Scala是动态类型"和"Scala是一种脚本语言".

我接受"Scala是[简单/复杂]"可能被认为是一个神话,但它也是一个非常依赖于上下文的观点.我个人认为,这些功能可以使Scala显得简单或复杂,具体取决于谁使用它们.最终,语言只提供抽象,而这就是用来塑造感知的方式.

不仅如此,它还有一定的激烈争论的倾向,而且我还没有看到有人改变对该主题的强烈观点......

mis*_*tor 40

神话:Scala的"选项"和Haskell的"可能"类型不会将你从null中拯救出来.:-)

Debunked:为什么Scala的"选项"和Haskell的"可能"类型会让 James Iry 免于你.

  • 有了免责声明,如果它实际使用,Option只会有所帮助.您仍然可以在Scala中获取空值,尤其是涉及Java互操作的地方. (4认同)
  • 也许Option应该扩展NotNull特性? (2认同)
  • @Gabe:同意,但这并不验证语句"Scala的'Option`类型不会使你从空值中保存".如果你使用它肯定会. (2认同)

Aar*_*rup 36

神话:Scala支持运算符重载.

实际上,Scala只有非常灵活的方法命名规则和用于方法调用的中缀语法,当中缀语法与'运算符'一起使用时,具有确定方法优先级的特殊规则.与真正的操作符重载(一个C++)相比,这种微妙的区别对于滥用这种语言特性的效用和潜在性具有重要意义,正如James Iry对这个问题的回答中更详细地解释的那样.

  • @Cevin:够公平的. (2认同)

Mar*_*sky 32

我不同意Scala很难的论点,因为你可以使用非常高级的功能来完成它.Scala的可伸缩性意味着您可以在Scala中编写DSL抽象和高级API,否则需要语言扩展.所以公平地说,你需要将Scala库与其他语言编译器进行比较.人们并没有说C#很难,因为(我认为,没有关于此的第一手资料)C#编译器非常难以理解.对于Scala来说,这一切都在公开场合.但是我们需要明确一点,我们明确表示大多数人不需要在这个级别编写代码,他们也不应该这样做.

  • 我最喜欢学习Scala(并逐渐感染我的Java代码库)的一个原因是,虽然在一个层面它可以非常干净和简单,甚至可以编写代码,但还有很多其他强大的层次需要探索.后面的一些功能仍然超出我的范围,但这只是意味着我需要学习的东西,这很酷!如果这种力量导致我的鞋子偶尔出现弹孔,那么,Scala限制我使用六射手,不像Perl所提供的Uzi.;-) (17认同)
  • 马丁他自己这个非常好的帖子:http://lamp.epfl.ch/~odersky/blogs/isscalacomplex.html (6认同)
  • 我不禁同意.如果一个工具很复杂,因为它允许你制作复杂的东西,那么你还必须在这样的定义下包括minecraft和lego.这对我来说非常违反直觉. (4认同)

oxb*_*kes 28

我认为许多scala开发人员,EPFL(以及你自己,Kevin)的常见误解是"scala是一种简单的语言".这个论点通常是这样的:

  • scala 关键字很少
  • scala重用相同的几个构造(例如,PartialFunction语法用作catch块的主体)
  • scala有一些简单的规则,允许您创建库代码(可能看起来好像该语言具有特殊的关键字/结构).我在想这里的含义; 含有冒号的方法; 允许的标识符号; 提取器的等价性X(a, b)a X b提取器的等价性.等等
  • scala的声明 - 站点差异意味着类型系统只是偏离你的方式.没有更多的通配符和? super T

我个人认为,这种说法完全是彻头彻尾的假.Scala的类型系统与implicits一起使用允许人们普通开发人员编写坦率的难以理解的代码.无论上述"指标"可能引导您如何思考,任何其他建议都是荒谬的.(请注意,那些我在Twitter和其他地方嘲笑Java的非复杂性的人恰好是超级聪明的类型,有时看起来,他们在他们出现之前已经掌握了monad,functor和arrows裤子).

反对这一点的明显论据是(当然):

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

其中,在我看来,只有#2是有效的.无论你是否编写与scalaz一样复杂的代码,我认为使用该语言(并继续使用它)并没有真正理解类型系统是愚蠢的.如何才能充分利用语言?

  • 我想我会说出自己的信念,因为"scala不必复杂",而不是"scala很简单".鉴于图灵完全混淆的可能性,如果您愿意,任何语言都可能变得复杂.Scala具有很大的KISS设计潜力,没有沉重的样板负担,这不是坏事! (8认同)
  • "X(a,b)和X b的等价"?不,等价是aX(b)和X b. (4认同)
  • @Landei - *叹气*.你错了.尝试一下,或者只看Daniel的答案:http://stackoverflow.com/questions/1059145/how-is-this-case-class-match-pattern-working/1059161#1059161 (3认同)
  • 基于关键字等的论证至少比"查看这个混淆代码的例子"更具实质性. (2认同)
  • @oxbow_lakes:你真的**读过**我的答案吗?我已经说过关于提取器和模式匹配你是对的,只是从你写它的方式来看你的意思并不是很明显(至少对我来说不是这样).但是**有**在List中定义的两个方法:`def ::(x:A):List [A]`和`def :: [B>:A](x:B):List [B]` ,它们是正常的"用例"(当你没有模式匹配时),按照我的说法工作,所以我建议你去看看ScalaDocs,然后再这么自信. (2认同)

Aar*_*rup 25

神话:方法和功能是一回事.

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

  • 只有方法可以有类型参数
  • 只有方法才能采用隐式参数
  • 只有方法可以有命名和默认参数
  • 当引用方法时,通常需要下划线来区分方法调用和部分函数应用程序(例如,str.length求值为数字,同时str.length _求值为零参数函数).


Rex*_*err 20

有一个神话,Scala很难,因为Scala是一种复杂的语言.

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

但无可否认,Scala代码难以理解.如果Scala不是一种复杂的语言,怎么会这样呢?

答案是Scala是一种强大的语言.与Java不同,Java有许多特殊结构(如枚举)可以完成一件特殊的事情 - 并且需要你学习仅适用于那一件事的专用语法,Scala有很多非常通用的结构.通过混合和匹配这些结构,人们可以用非常少的代码表达非常复杂的想法.而且,不出所料,如果有人出现并没有同样复杂的想法,并试图弄清楚你正在用这个非常紧凑的代码做什么,他们可能会发现它令人生畏 - 甚至比他们看到一对夫妇更令人生畏那些代码页面做同样的事情,从那以后至少他们会意识到有多少概念性的东西需要理解!

还有一个问题是事情是否比他们真正需要的更复杂.例如,集合库中存在的一些类型体操使得集合使用起来很愉快,但是难以实现或扩展.这里的目标并不是特别复杂(例如,子类应该返回它们自己的类型),但是所需的方法(更高级的类型,隐式构建器等)是复杂的.(事实上​​,如此复杂,Java只是放弃而不是尝试,而不是像Scala那样"正确"地执行它.而且,原则上,希望这将在未来得到改善,因为该方法可以发展更接近目标.)在其他情况下,目标是复杂的;list.filter(_<5).sorted.grouped(10).flatMap(_.tail.headOption) 有点乱,但如果你真的想把所有数字都小于5,然后在剩下的列表中取10个中的每个第二个数字,那么,这只是一个有点复杂的想法,而且代码几乎说了什么如果你知道基本的集合操作就会这样.

简介:Scala并不复杂,但它允许您紧凑地表达复杂的想法.复杂思想的紧凑表达可能令人生畏.


有一个神话认为Scala是不可部署的,而可以毫不犹豫地部署各种第三方Java库.

在这个神话存在的范围内,我怀疑它存在于那些不习惯将虚拟机和API与语言和编译器分离的人中.如果你认为java == javac == Java API,如果有人建议使用scalac而不是javac,你可能会有点紧张,因为你看到你的JVM运行得有多好.

Scala最终成为JVM字节码,加上自己的自定义库.没有理由担心在小规模上部署Scala或者作为其他大型项目的一部分,因为部署任何其他库可能会或可能不会与您喜欢的任何JVM保持兼容.当然,Scala开发团队没有像Google集合或Apache Commons那样强大的支持,但它至少与Java Advanced Imaging项目相比具有同样重要的作用.

  • 这里的Dijkstra引用似乎是合适的:*编程仍然非常困难,因为一旦我们摆脱了间接的麻烦,我们就会发现自己可以自由地解决现在远远超出我们编程能力的问题.*可能是这样的情况Scala删除了足够的麻烦,我们现在只是看到它被用于本身更复杂的问题,而这种复杂性与语言有关吗? (14认同)

Arn*_*rne 16

神话:

def foo() = "something"
Run Code Online (Sandbox Code Playgroud)

def bar = "something"
Run Code Online (Sandbox Code Playgroud)

是一样的.

它不是; 你可以调用foo(),但bar()尝试不带参数调用StringLike的apply方法(导致错误).


Vas*_*iuk 14

与Actors库有关的一些常见误解:

  • Actors以并行,多线程/针对线程池处理传入消息(实际上,处理多个线程中的消息与actor概念相反并且可能导致竞争条件 - 所有消息在一个线程中顺序处理(基于线程) actor使用一个线程进行邮箱处理和执行;基于事件的actor可以共享一个VM线程执行,使用多线程执行程序来安排邮箱处理))
  • 未捕获的异常不会改变actor的行为/状态(实际上,所有未捕获的异常都会终止actor)

  • 在基本配置中,Scala actor由ThreadPoolExecutor(ExecutorScheduler)支持.确保暂停的actor将在同一个线程上恢复.当使用SingleThreadScheduler支持actor时,所有actor任务都在同一个线程上执行. (5认同)
  • 许多人总体上混淆了并发性和并行性.这也可能是潜在的误解. (2认同)

Aar*_*rup 14

误区:在从零开始计算总和时,可以用reduce替换折叠.

这是Scala的新用户中常见的错误/误解,特别是那些没有先前函数编程经验的用户.以下表达式相同:

seq.foldLeft(0)(_+_)

seq.reduceLeft(_+_)
Run Code Online (Sandbox Code Playgroud)

这两个表达式在处理空序列的方式上有所不同:fold产生有效结果(0),而reduce则抛出异常.


mis*_*tor 12

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

马丁奥德斯基亲自在这里揭穿.(另见本文 - 与模式匹配的对象 - 由Odersky等人提出)


Aar*_*rup 9

神话:this.type指的是同一类型this.getClass.

作为这种误解的一个例子,可以假设在以下代码中的类型v.meB:

trait A { val me: this.type = this }

class B extends A

val v = new B
Run Code Online (Sandbox Code Playgroud)

实际上,this.type指的是其唯一实例的类型this.通常,x.type是唯一的实例是单例类型x.所以在上面的例子中,类型v.mev.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"
Run Code Online (Sandbox Code Playgroud)


Vas*_*iuk 7

Scala具有类型推断和细化类型(结构类型),而Java则没有.

神话被捣毁詹姆斯IRY.