为什么“避免方法重载”?

为什么豪尔赫·奥尔蒂斯build议避免方法重载?

重载使得将一个方法提升到一个函数有点困难:

object A { def foo(a: Int) = 0 def foo(b: Boolean) = 0 def foo(a: Int, b: Int) = 0 val function = foo _ // fails, must use = foo(_, _) or (a: Int) => foo(a) } 

您不能有select地导入一组重载的方法之一。

尝试应用隐式视图以使参数适应参数types时,出现歧义的可能性较大:

 scala> implicit def S2B(s: String) = !s.isEmpty S2B: (s: String)Boolean scala> implicit def S2I(s: String) = s.length S2I: (s: String)Int scala> object test { def foo(a: Int) = 0; def foo(b: Boolean) = 1; foo("") } <console>:15: error: ambiguous reference to overloaded definition, both method foo in object test of type (b: Boolean)Int and method foo in object test of type (a: Int)Int match argument types (java.lang.String) object test { def foo(a: Int) = 0; def foo(b: Boolean) = 1; foo("") } 

它可以安静地呈现默认参数不可用:

 object test { def foo(a: Int) = 0; def foo(a: Int, b: Int = 0) = 1 } 

个别地,这些原因不会迫使你完全避免超载。 我觉得我错过了一些更大的问题。

UPDATE

证据堆积如山。

  • 这使规格复杂化
  • 它可能使得implicits不适合在视图边界中使用。
  • 它限制了您仅在一个重载的备选scheme中引入参数的默认值。
  • 因为参数的types没有预期的types,所以你不能传递像'_.foo'这样的匿名函数文字作为重载方法的参数 。

更新2

  • 你不能(当前)在包对象中使用重载的方法。
  • 适用性错误更难以诊断您的API的调用者。

更新3

  • 静态重载分辨率可以抢夺所有types安全的API:

    scala> object O {def apply [T](ts:T *)=(); def apply(f:(String => Int))=()}定义的对象O.

    ());我想打电话给第二个重载,但有人改变了f的返回types,当我不看…

Gilad和Jason(retronym)给出的原因都是尽可能避免超载的很好的理由。 吉拉德的原因集中在为什么超载是一般问题,而杰森的原因集中在为什么在其他Scalafunction的问题。

对于Jason的名单,我想补充一点,过载与types推断的交互作用很差。 考虑:

 val x = ... foo(x) 

x的推断types的改变可以改变哪个foo方法被调用。 x不需要改变,只是x的推断types,可能由于各种原因而发生。

由于所有给出的理由(还有一些我确定我忘了),我认为应该尽可能节省方法重载。

我认为这个build议不是特别针对scala,而是针对面向对象的一般(到目前为止,我知道scala应该是面向对象和function之间的一个最好的)。

重写是好的,它是多态的核心,是面向对象devise的核心。

另一方面, 超载更成问题。 使用方法重载很难判断哪个方法会被真正调用,而且确实经常是一个混淆的来源。 为什么超载真的是必要的,也很less有理由。 问题可以在大多数时候以另一种方式解决,我同意超载是一种气味。

这里有一篇文章很好地解释了我的意思是“超载是一个混乱的根源”,我认为这是造成这种情况的主要原因。 这是为Java,但我认为它也适用于Scala。