为什么Scala支持影子变量?

5

我认为影子变量太危险了,不应该使用它们。为什么Scala支持这种语言结构?必须有一些强烈的原因,但我找不到。


1
我曾经也想过同样的事情。也许Odersky等人只是没有考虑地从Java中延续了这种行为。 - laher
我相信Odersky先生对于任何具体语言结构的决策都有一定的动机。 :) - Igor Soloydenko
好的,我猜他认为编译器警告已经足够了。我可以看到scalac有一个编译器选项-Ywarn-shadowing,所以理论上IDE也支持它。 - laher
@amir75 实际上,所有-Y的工作都是Paul Phillips完成的,并且在某种程度上具有实验性质。如果它存在,那是因为它对他实际上非常有用。 - Daniel C. Sobral
我看到这是旧的,但是... 这是我最近读过的最奇怪的问题。那么替代方案会是什么呢?一个被每个导入的库大量污染的巨大全局作用域?奇怪的变量和函数名,比如glDrawStuff或cvSeeStuff吗? - Andrey Tyukin
2个回答

23
提醒一下:当在内部作用域中声明变量、方法或类型时,使得无法以非限定的方式(有时完全无法)引用外部范围的同名实体,则称变量、方法或类型“阴影”另一个同名变量、方法或类型。与Java一样,Scala也允许阴影。
我可以想到的一个可能原因是,在Scala中,经常有许多嵌套的作用域,每个作用域都相对较短(与Java或C ++等语言相比)。实际上,块可以在任何期望表达式的地方开始,从而开始一个新的作用域。在内部作用域中使用阴影名称通常更接近它们的声明,并且更不会产生歧义。
此外,在线闭包经常使程序员需要在已经拥挤的作用域中使用新的变量名。允许阴影还允许继续使用描述性名称,即使它们与已使用的名称相同,也足够明确,而不是发明其他奇怪的名称-例如,给它们加前缀为my、local,或者(更糟糕的是)_ 或单字母名称。
使用好的IDE后,阴影问题会减少,因为IDE可以在源代码中突出显示光标下变量的声明和引用。
以上仅代表个人意见。

1
感谢您详细的回复和提醒,我没有提供。我考虑了闭包上下文中的变量遮蔽。您说得对,一些开发人员可能会在闭包作用域中使用相同的名称,而不是给出一些新的名称。我猜这些开发人员只是觉得使用起来更舒适。但这不是一个隐藏的威胁吗?我同意为短范围变量的名称添加前缀并不完美。但在大多数情况下(特别是对于Scala新手),它使代码更易于理解。如果我错了,请纠正我。 - Igor Soloydenko

19

我认为使用影子变量太危险了。

你有权利持有任何想法。然而,由于你没有提供任何数据、研究或甚至理由,所以那个意见毫无价值。

为什么Scala支持这种语言结构?

因为它是有用的。程序员不需要发明任意标识符名称,只因为一些作用域内的标识符已经在使用中。

它还使通配符导入更加有用,因为它消除了编译故障的可能性,只因为第三方添加了一个您正在使用的标识符。

应该有一些强有力的理由才对,但我找不到。

为什么必须有充足的理由呢?它有优点,在没有缺点的情况下(你没有提出任何),这就足够了。

编辑

回答中解释的缺点问题,我必须说这是一种特殊情况的遮蔽。遮蔽还会影响到所有导入,无论是通过import语句还是嵌套的package语句,以及在同一包中的所有内容。

让我们来看一些例子:

// Not allowed, because it shadows List
import java.util._ 

class A {
    // Not allowed, because it shadows this, hashCode, equals, toString
    class B
}
那会变成一门非常烦人的语言。

1
变量影子的危险太明显了,无法在初始问题中描述。顺便说一下,我已经在对Jean-Philippe的回答的评论中写过了(可能你没有看过)。但是为了你特别重申一遍。 - Igor Soloydenko
4
当某人在某个作用域中声明一个变量,并且这个变量与外部作用域中的另一个变量同名时,会使代码更加复杂。追踪每个变量的含义变得更加困难。以下是《Scala编程》一书中的好引用:“请记住,这样的代码对读者来说可能非常令人困惑,因为变量名称在嵌套作用域中采用了新的含义。通常最好选择一个新的、有意义的变量名,而不是遮蔽一个外部变量。” - Igor Soloydenko
@keykeeper 好的,我已经回答了那个论点。 - Daniel C. Sobral

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接