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

时间:2010-03-24 17:45:41

标签: scala overloading

3 个答案:

答案 0 :(得分:102)

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

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)
}

您无法有选择地导入一组重载方法。

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

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 
}

单独地,这些原因并不会迫使您完全避免重载。我觉得我错过了一些更大的问题。

<强>更新

证据正在堆积。

更新2

  • 您不能(当前)在包对象中使用重载方法。
  • API的来电者的适用性错误为harder to diagnose

更新3

  • 静态重载解析可以抢夺所有类型安全的API:
scala> object O { def apply[T](ts: T*) = (); def apply(f: (String => Int)) = () }
defined object O

scala> O((i: String) => f(i)) // oops, I meant to call the second overload but someone changed the return type of `f` when I wasn't looking...

答案 1 :(得分:8)

Gilad和Jason(反语)给出的理由是尽可能避免超载的理由。 Gilad的理由主要集中在为什么一般会出现重载问题,而Jason的理由则集中在为什么它在其他Scala功能的背景下存在问题。

对于Jason的列表,我想补充一点,重载与类型推断的交互性很差。考虑:

val x = ...
foo(x)

x的推断类型的更改可能会改变调用哪个foo方法。 x无需更改,只需推断x的推断类型,这种情况可能因各种原因而发生。

由于给出的所有原因(还有一些我确定忘记了),我认为方法重载应该尽量少用。

答案 2 :(得分:1)

我认为这个建议并不适用于scala,但对于一般的OO(到目前为止,我知道scala应该是OO和功能之间的最佳选择)。

覆盖很好,它是多态性的核心,也是OO设计的核心。

另一方面,

重载更成问题。使用方法重载时,很难辨别哪个方法将被真正调用,而且它确实经常成为混淆的来源。也很少有理由说明为什么过载是非常必要的。这个问题大部分时间都可以通过另一种方式解决,我同意重载是一种气味。

这里是an article,很好地解释了我的意思,“重载是一个混乱的来源”,我认为这是其沮丧的主要原因。它适用于java,但我认为它也适用于scala。