2009-07-17 46 views
2

为什么这么多的编程语言使得函数可以将传递给它的对象作为参数进行修改,而不需要某种语法来使调用者清楚。例如考虑:清除函数可以修改其参数

SomeObject A(15), B 
B = DoSomething(A) 
print(A + " " + B + "\n) 

读取代码,你会希望输出是类似于“15 75”,即A是你构造它。然而,大多数语言都可以让DoSomething改变A.在C++中,你可以通过查看DoSomething的声明来判断它是否可能,例如通过查看参数被定义为非const引用。然而,在很多语言中,比如Python,如果没有阅读函数的代码以确保它永远不会改变,真的没有办法告诉A.

我很多次被这个问题困扰过,特别是在尝试工作时与别人的代码使用这种行为,通常会导致贯穿整行代码逐行尝试并找到什么改变参数...

为什么它是语言通常不需要一些显式语法通过调用说“是的,这个对象可以修改”,例如说“B = DoSomething(inout A)”?

是否有任何编码标准有助于防止问题发生,除了“从不修改传入函数的参数”?

+1

选择一种语言; “这么多的编程语言”是很多语言,每种语言的设计决定都不一样。 – 2009-07-17 07:43:38

+0

Python,C,C++,Java都可以完全按照我的示例中所示的那样进行,我怀疑还有很多我不知道/使用的东西。 – 2009-07-17 12:06:52

回答

1

“编码标准”因语言和用户/团队而异。 C++具有常量正确性,当正确使用时,它就是编码标准。对于明显的情况,C#有outref参数。我认为在各种语言中唯一真正的一致性是参数修改应始终记录在函数的后置条件中。

+0

是的,但在将C++中的每个变量传递给函数之前,人们很少会将其转换为const类型,并且如我的示例中所示,从调用代码中看不到参考传递,您需要查看函数定义(它与现代IDE并不难,但仍然需要检查每个函数,而不是浏览代码)。 当我看了一些像我的例子那样的代码时,文档仍然不突出,你必须去查看它。 – 2009-07-17 11:58:34

1

如果你看看Java,一种方法不能真正改变参数(Java只有输入参数)。但是参数通常只是对某个对象的引用,这意味着该方法可以以任何可能的方式更改对象。这使得关于语义的推理(不看文档)变得困难,这与函数编程完全相反。

你是对的,这是不可取的,但在短期内它使事情变得更容易。不幸的是,大多数情况下它是短期的重要,所以我们仍然在使用支持隐藏副作用的语言......

+0

即使有规则。作为一个简单的例子,getter不应该改变程序状态,所以你通常可以假设你正在阅读代码。 – 2009-07-17 07:37:36

+0

这对于POD类型也不适用。 – scorpiodawg 2015-05-13 03:02:08

0

这并不直接使您的代码片段更清晰,但我仍想提及它:我们使用参数的命名约定来准确显示您想要的内容。我们使用'in','out'和'io'前缀。所以DoSomething声明看起来像DoSomething(ioSomeObject inA)。在Visual Studio中使用Visual Assist工作时,您将看到一个弹出窗口,其中包含参数的类型和名称,并记录了可能的副作用。在我看来,这比记录后期条件更为明显。

问候,

Sebastiaan

1

我给该优选的设计模式是不可变的数据类。

使用可变类时,您必须考虑是否被修改。

根据我的理解,一个澄清点就是像Java和C(没有修饰符)那样传递值。但是你传递的通常是一个可变对象。

(编辑:。几乎所有的主流语言遵循这些语义现在最突出的例外是Lisp的,在这里你不仅可以修改可变对象,但重新分配的值由变量指向)