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


78

它与Scala继承Java的类型擦除有关吗?
贾斯汀·涅斯纳

1
@贾斯汀:类型擦除与这有什么关系?
missingfaktor

6
您为什么不问Jorge Ortiz为什么建议不要重载方法?
约翰

不知道,因为我不知道乔治的原意,但它的适用:michid.wordpress.com/2008/02/08/...
贾斯汀Niessner

12
呸... bit.ly/aduyIn:'(
missingfaktor

Answers:


108

重载使将方法提升为功能更加困难:

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的调用者来说,适用性错误很难诊断

更新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...

2
当前,在某些情况下,超载也会触发scalac中的错误。issues.scala-lang.org/browse/SI-7596
cvogt

2
前两个问题不会影响过载的所有有效使用。提交第三期的错误报告默认值限制是由选择决定的,理论上可以是固定的。该故障_.foo问题是Scala的有限的类型推断,没有超载。您回答了这个问题,但是某些原因是由于Scala中的其他弱点可以改善。重载比运行时向下转换析取关系更有效,或者名称的笛卡尔乘积嘈杂并且与共享语义断开连接比重载更为有效。
谢尔比·摩尔三世

3
由于缺少一等联合类型,当前无法普遍使用类型类。是的,我看到Scala的社会表明态度,但想象代替addIntToDoubleaddDoubleToInt即一个名称,而不是每一个公共语义静态类型的笛卡尔乘积。用命名代替打字似乎是回归的。Java正确的事情比我们可能认识的要多。
谢尔比·摩尔三世

2
在讨论线程中写过(对于我在先前的评论中提到的错误报告),“ IMO所期待的是邪恶的,而不是过载,或者降低了为通用语义使用一个名称的重要性”。
谢尔比·摩尔三世

2
答案和评论对我来说似乎很幼稚,没有提及使用重载的最重要的单一原因:方法必须根据传递给它的类型实际执行非常不同的内部逻辑时。“使用隐式”的答案立即失败,因为可能不存在从一个对象到体现专用逻辑的另一种类型的任何可能转换。
ely

8

Gilad和Jason(重新命名)给出的原因都是避免过载的很好理由。吉拉德(Gilad)的原因集中于为什么重载通常是有问题的,而杰森(Jason)的原因集中于为什么在其他Scala功能的上下文中重载是有问题的。

在Jason的列表中,我要补充一点,重载与类型推断的交互作用很差。考虑:

val x = ...
foo(x)

推断类型的x更改可能会更改foo调用哪个方法。该x需求不会改变,只是推断类型的x,这可能发生的各种原因。

由于给出的所有原因(还有更多我敢忘的原因),我认为应尽量少使用方法重载。


2
如果您不希望发生这种情况,请声明x的类型。如果您未声明,则表示您希望更改它。foo对于具有相同数量的参数的每个重载,的语义应相同,否则它的设计不正确。至于限制推理更改的怪异级联的范围,公共方法应始终声明其返回类型。我认为这是影响版本之间Scala二进制兼容性的问题之一。
谢尔比·摩尔

1

我认为建议不是特别针对scala的,而是针对OO的(到目前为止,我知道scala应该是OO和功能之间的最佳选择)。

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

另一方面,过载更成问题。使用方法重载很难辨别哪个方法将被真正调用,并且确实经常引起混淆。也很少有理由说明为什么确实需要重载。大多数时候,问题可以用另一种方法解决,我同意超载是一种气味。

这里的一篇文章很好地解释了“超载是混乱的根源”的含义,我认为这是不鼓励这样做的主要原因。它适用于Java,但我认为它也适用于Scala。


2
无论如何,Scala并不是主要的OO语言。
Daniel Earwicker

4
@ewenli-Jorge在scala社区中是众所周知的,Rahul提供的链接是Jorge的scala技巧之一,但是您的答案无济于事,为什么超载对scala不利,这显然是问题的意图。另外,我也不知道您为什么认为这个问题很困惑-您应该从答案中删除这个问题,因为这是完全没有道理的。-1
oxbow_lakes 2010年

6
@Daniel Scala的主要是一个面向对象的语言。您为什么不这么认为呢?
Daniel C. Sobral'3

3
哦,竞争性功能语言的创建者认为Scala的功能还不够!大震撼!:)
Daniel Earwicker 2010年

3
@Daniel Scala可能是多种范例,但它仍然主要还是一种面向对象的语言。Scala的功能特性被实现面向对象的功能。即使是功能最强大的Scala程序也将仅由对象及其各自的类和特征组成。现在,马丁·奥德斯基(Martin Odersky)可能会说出他想说的任何语言(毕竟这是他的语言),但是在严格的技术评估中,Scala主要是面向对象的,其中“主要”是指其他所有内容都基于此特性。
Daniel C. Sobral
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.