为什么“避免方法重载”?
为什么豪尔赫·奥尔蒂斯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。