为什么 Scala 编译器不允许使用默认参数的重载方法?
虽然在某些有效情况下,此类方法重载可能会变得不明确,但为什么编译器不允许在编译时和运行时都不是不明确的代码呢?
例子:
// This fails:
def foo(a: String)(b: Int = 42) = a + b
def foo(a: Int) (b: Int = 42) = a + b
// This fails, too. Even if there is no position in the argument list,
// where the types are the same.
def foo(a: Int) (b: Int = 42) = a + b
def foo(a: String)(b: String = "Foo") = a + b
// This is OK:
def foo(a: String)(b: Int) = a + b
def foo(a: Int) (b: Int = 42) = a + b
// Even this is OK.
def foo(a: Int)(b: Int) = a + b
def foo(a: Int)(b: String = "Foo") = a + b
val bar = foo(42)_ // This complains obviously ...
有什么理由不能让这些限制稍微放松一点吗?
特别是当将重载的 Java 代码转换为 Scala 时,默认参数非常重要,并且在用一种 Scala 方法替换大量 Java 方法后发现规范/编译器强加了任意限制,这一点并不好。
While there might be valid cases where such method overloadings could become ambiguous, why does the compiler disallow code which is neither ambiguous at compile time nor at run time?
Example:
// This fails:
def foo(a: String)(b: Int = 42) = a + b
def foo(a: Int) (b: Int = 42) = a + b
// This fails, too. Even if there is no position in the argument list,
// where the types are the same.
def foo(a: Int) (b: Int = 42) = a + b
def foo(a: String)(b: String = "Foo") = a + b
// This is OK:
def foo(a: String)(b: Int) = a + b
def foo(a: Int) (b: Int = 42) = a + b
// Even this is OK.
def foo(a: Int)(b: Int) = a + b
def foo(a: Int)(b: String = "Foo") = a + b
val bar = foo(42)_ // This complains obviously ...
Are there any reasons why these restrictions can't be loosened a bit?
Especially when converting heavily overloaded Java code to Scala default arguments are a very important and it isn't nice to find out after replacing plenty of Java methods by one Scala methods that the spec/compiler imposes arbitrary restrictions.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
我想引用 Lukas Rytz(来自此处):
未来 Scala 版本的解决方案可能是将非默认参数(位于方法开头的参数,消除重载版本的歧义)的类型名称合并到命名模式中,例如在本例中
:会是这样的:
有人愿意编写 SIP 提案?
I'd like to cite Lukas Rytz (from here):
A solution for future Scala version could be to incorporate type names of the non-default arguments (those at the beginning of a method, which disambiguate overloaded versions) into the naming schema, e.g. in this case:
it would be something like:
Someone willing to write a SIP proposal?
对于重载解析与默认参数的交互,很难获得可读且精确的规范。当然,对于许多个别情况(例如这里介绍的情况),很容易说出应该发生什么。但这还不够。我们需要一个规范来决定所有可能的极端情况。重载分辨率已经很难指定。在混合中添加默认参数会使事情变得更加困难。这就是为什么我们选择将两者分开。
It would be very hard to get a readable and precise spec for the interactions of overloading resolution with default arguments. Of course, for many individual cases, like the one presented here, it's easy to say what should happen. But that is not enough. We'd need a spec that decides all possible corner cases. Overloading resolution is already very hard to specify. Adding default arguments in the mix would make it harder still. That's why we have opted to separate the two.
我无法回答你的问题,但这里有一个解决方法:
如果你有两个很长的参数列表,其中只有一个参数不同,那么可能值得麻烦......
I can't answer your question, but here is a workaround:
If you have two very long arg lists which differ in only one arg, it might be worth the trouble...
对我有用的是重新定义(Java 风格)重载方法。
这可以确保编译器根据当前参数获得您想要的分辨率。
What worked for me is to redefine (Java-style) the overloading methods.
This ensures the compiler what resolution you want according to the present parameters.
这是 @Landei 答案的概括:
你真正想要的:
Workarround
Here is a generalization of @Landei answer:
What you really want:
Workarround
一种可能的情况是
编译器会对调用哪一个感到困惑。为了防止其他可能的危险,编译器最多允许一个重载方法具有默认参数。
只是我的猜测:-)
One of the possible scenario is
The compiler will be confused about which one to call. In prevention of other possible dangers, the compiler would allow at most one overloaded method has default arguments.
Just my guess:-)
我的理解是,使用默认参数值编译的类中可能存在名称冲突。我在几个线程中看到了类似的内容。
命名参数规范在这里:
http://www.scala-lang.org/sites/default/files/sids/rytz/Mon,%202009-11-09,%2017:29/named-args.pdf
它指出:
所以,无论如何,目前来说,这是行不通的。
你可以做一些类似于 Java 中的事情,例如:
My understanding is that there can be name collisions in the compiled classes with default argument values. I've seen something along these lines mentioned in several threads.
The named argument spec is here:
http://www.scala-lang.org/sites/default/files/sids/rytz/Mon,%202009-11-09,%2017:29/named-args.pdf
It states:
So, for the time being at any rate, it's not going to work.
You could do something like what you might do in Java, eg: