Java马丁 Odersky访谈录所思

Martin Odersky

ThoughtWorks的TW洞见在二月宣布了对Scala之父Martin
Odersky的访谈
。Odersky的回应出示切中时弊,仔细分析,还是能从中获得广大富含的新闻(即使或然是负面的音信)。提问的着力首若是言语之争。Scala是一门极具吸重力的言语,就像是天生具备一种气质,轻易能够吸粉,但招黑的力量也一点也不逊色。它好似是从象牙塔里钻研出来的,但又在无数大型项目和产品中赢得了执行。有人转向了她,又有人之后背弃了它。假若说Ruby的助力是Rails,那么推动着Scala在社区中成长的,其实处处可知斯Parker的阴影。

唯独,一个两难的现状是,Spark的居多源代码并不曾如约Scala推崇的特级实践。Odersky对此的演讲是:

斯Parker的API设计是和Scala
集合类设计是相同的函数式风格,里面具体的达成为了追求品质用了命令式,你能够看出Scala集合里面包车型地铁贯彻函数为了品质也用了很多var。

那或者是Scala采纳多范式的重点缘由吧。即便Scala借鉴了广大函数式语言的表征,例如Scheme和Haskell,但Scala并不曾强制我们在编辑代码时严谨服从FP的条件。大家须要在OO与FP之间画一条线。在代码的细节层面,Scala须求大家大力编写没有副功能(引用透明),提供组合子抽象的函数式风格代码;但是在局地景况下,又同意大家让位于OO的当家。

Scala属于语言中的“骑墙派”,只要您足足高明,就可见在OO与FP中跳转如意,怡然自得,如虎傅翼。所谓“骑墙”,反倒成了具备超强适应能力的“八面玲珑”,何乐不为?

Odersky在访谈中推荐了Databricks给出的Scala编码规范,还有lihaoyi的文章Strategic
Scala Style: Principle of Least
Power

设若大家阅读Databricks给出的编码规范,会发现Databricks为了品质考虑,更赞成于选取命令式形式去接纳Scala,例如,规范建议利用while循环,而非for循环只怕其余函数转换(map、foreach)。

val arr = // array of ints
// zero out even positions
val newArr = list.zipWithIndex.map { case (elem, i) =>
  if (i % 2 == 0) 0 else elem
}

// This is a high performance version of the above
val newArr = new Array[Int](arr.length)
var i = 0
val len = newArr.length
while (i < len) {
  newArr(i) = if (i % 2 == 0) 0 else arr(i)
  i += 1
}

不过就本身个人的习惯,更倾向于前者(使用zipWithIndex结合map),它采纳特别简洁的函数式风格。鱼与熊掌,不可兼得!那是1个标题!规范从可读性角度考虑,不建议利用Monadic
Chaining。例如,下边的代码应用三番五次多个flatMap:

class Person(val data: Map[String, String])
val database = Map[String, Person]()
// Sometimes the client can store "null" value in the  store "address"

// A monadic chaining approach
def getAddress(name: String): Option[String] = {
  database.get(name).flatMap { elem =>
    elem.data.get("address")
      .flatMap(Option.apply)  // handle null value
  }
}

规范提议,改写为更富有可读性的主意:

// A more readable approach, despite much longer
def getAddress(name: String): Option[String] = {
  if (!database.contains(name)) {
    return None
  }

  database(name).data.get("address") match {
    case Some(null) => None  // handle null value
    case Some(addr) => Option(addr)
    case None => None
  }
}

即便采纳方式匹配(帕特tern
Match)确实是很好的Scala实践,但就这么些事例而言,其实Monadic
Chaining的不二法门得以用for comprehension来改写。相当简短,可读性极佳:

for {
    elem <- database.get(name)
    addr <- elem.data.get("address")
} yield addr

那么,那样的规范是或不是是好的Scala实践吧?Odersky用“保守”一词来评论这一规范,不知其本意如何?

lihaoyi的文章Strategic Scala Style: Principle of Least
Power
不是七个正式,而是一份Scala最佳实践。内容包涵对不变性与可变性、接口设计、数据类型、格外处理、异步、注重注入的分析与提出。值得一读。

Martin Odersky提纲契领地付诸了多少个编写Scala代码的尺度:

  • 尽恐怕用力量弱的效应;
  • 给中间步骤命名。

对于第③点,作者个人的知道是在接纳Scala天性的时候,要注意控制,不要去作弄Scala语法中那些奇技淫巧,从而让代码变得别扭难懂。推特(TWTR.US)的一对工程师之所以对scala抱有牢骚,多数吐槽点正是在代码的可读性与维护性方面。第1点同样是为着消除此难题。推文(Tweet)的文书档案Effective
Scala
用例子阐释了为中等步骤命名的主要。如下例子:

val votes = Seq(("scala", 1), ("java", 4), ("scala", 10), ("scala", 1), ("python", 10))
val orderedVotes = votes
  .groupBy(_._1)
  .map { case (which, counts) => 
    (which, counts.foldLeft(0)(_ + _._2))
  }.toSeq
  .sortBy(_._2)
  .reverse

那样的代码固然不难,却无法从心所欲地反映作者的企图。假使正好地予以中间步骤命名,意义就越发理解了。

val votesByLang = votes groupBy { case (lang, _) => lang }
val sumByLang = votesByLang map { case (lang, counts) =>
  val countsOnly = counts map { case (_, count) => count }
  (lang, countsOnly.sum)
}
val orderedVotes = sumByLang.toSeq
  .sortBy { case (_, count) => count }
  .reverse

Odersky在访谈中谈到了有的对以往Scala的筹划,包涵Tasty与Dotty,前者是为了消除Scala二进制不包容难题,Dotty则是为Scala提供新的编写翻译器。但是,Odersky的应对令人失落,二者的实在生产还须要拭目以待几年时光。

几年时间啊!再过几年,Scala会否成为明天黄花呢?至少Java的前进趋势已经上马勒迫Scala了。而JVM的多变是还是不是又会越加为Scala的反复无常造成障碍吗?倘诺还要考虑版本包容难点,Scala的前程版本碰到堪忧啊。想想笔者都为Odersky感到胃痛啊。

只是Scala又不可能离开JVM,不然Scala与Java包容带来的有益就没有了。庞大的Java社区直接是Scala能够汲取的财富呢。Scala会否成也JVM,败也JVM呢?

Java,坦白说,这几个访谈没有提供太多Scala的养分(不知是还是不是翻译的标题),总以为Odersky在直面有些有关语言的深深难点时,显得闪烁其词。固然Odersky搬出了沃尔玛美利坚合众国、高盛、MorganStanley来压阵,却反给作者底气不足的感到。Scala不佳的有个别如故太多了,它会妨碍大家对Scala做出正确地看清。Scala待消除的标题依然太多了,lightbend任重先生而道远。百川归海,从一发轫,Odersky没有对Scala性子做出具有控制力的筹划,贫乏收敛,导致众多feature长短不一,败坏了Scala的声名。

幸好有二个Spark,是Spark拯救了Scala。可惜,斯Parker的编码规范却不持有Scala范儿。


题图:来自ThoughtWorks洞见小说《SCALA之父MAPRADOTIN
ODECR-VSKY访谈录》中的马丁 Odersky。

相关文章