明确函数可以修改其参数
为什么如此多的编程语言使得函数可以修改作为参数传递给它的对象,而无需某种语法来让调用者清楚地了解这一点。 例如,考虑一下:
SomeObject A(15), B
B = DoSomething(A)
print(A + " " + B + "\n)
阅读该代码,您会期望输出类似于“15 75”,即 A 是您构造它的结果。 然而,大多数语言都允许 DoSomething 更改 A 的值。在 C++ 中,您可以通过查看 DoSomething 的声明来判断其是否可能,例如通过查看参数是否定义为非常量引用。 然而,在许多语言中,例如Python,如果不通读函数的代码以确保它永远不会改变,实际上是没有办法判断的。
我已经被这个问题困扰过几次了,尤其是在尝试使用别人的代码时它使用这种行为,通常会导致逐行浏览整段代码来尝试找到正在更改参数的内容...
为什么语言通常不需要通过调用说“是的这个”来使用一些显式语法对象可以被修改”,例如说“B = DoSomething(inout A)”?
除了“永远不要修改传递给函数的参数”之外,是否有任何编码标准可以帮助防止问题发生?
Why is it that so many programming languages make it possible for a function to modify an object passed to it as a parameter, without having some sort of syntax to make that clear to the caller. Eg consider:
SomeObject A(15), B
B = DoSomething(A)
print(A + " " + B + "\n)
Reading that code you would expect the output to be something like "15 75", ie A is what you constructed it to. However most languages make it possible for DoSomething to change the value of A. In C++ you can tell if its possible or not by looking at the declaration of DoSomething, eg by looking is the parameter is defined as a non const reference. However in many languages, such as Python there is really no way to tell without reading through the code for the function to make sure it never changes A.
Ive been bitten by this on a few occasions, especially when trying to work with someone else's code which uses this behaviour and usually results in going through the entire piece of code line by line to try and find what's changing the parameter...
Why is it that languages don't generally require some explicit syntax by the calling to say "yes this object can be modified", eg say "B = DoSomething(inout A)"?
Is there any codeing standards that help to prevent problems occurring, apart from the "never modify a parameter passed into the function"?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
如果你看看Java,方法并不能真正改变参数(Java只有输入参数)。 但参数通常只是对某个要使用的对象的引用,这意味着该方法可以以任何可能的方式更改该对象。 这使得推理语义(不查看文档)变得困难,这与函数编程完全相反。
你说得对,这是不可取的,但在短期内它让事情变得更容易。 不幸的是,大多数情况下,重要的是短期,因此我们仍在使用支持隐藏副作用的语言......
If you look at Java, a method can not really change the parameter (Java has only input parameters). But the parameter is often just a reference to some object to work with, which means that the method can change the object in any possible way. This makes reasoning about the semantics (without looking at docs) hard, quite the opposite to function programming.
You are right that this is undesirable, but in the short term it made things easier. Unfortunately, most often it is short term what counts, so we are still working with languages that support hidden side effects...
“编码标准”因语言和用户/团队而异。 C++ 具有常量正确性,如果使用得当,它可以被视为编码标准。 对于明显的情况,C# 有
out
和ref
参数。 我想说,各种语言之间唯一真正的一致性是参数修改应始终记录在函数的后置条件中。The "coding standards" vary by language and among users/teams. C++ has const-correctness, which when properly used counts as a coding standard. C# has
out
andref
parameters for obvious cases. I'd say the only real consistency across a wide range of languages is the fact that parameter modifications should always be documented in the post-conditions of the function.我首选的设计模式是不可变数据类。
对于可变类,您必须考虑它是否会被修改。
需要澄清的是,根据我的理解,Python 是按值传递的,就像 Java 和 C 一样(不带修饰符)。 但你传递的通常是一个可变对象。
(编辑:现在几乎所有主流语言都遵循这些语义。最突出的例外是 Lisp,您不仅可以修改可变对象,还可以重新分配变量指向的值。)
My preferred design pattern for this is immutable data classes.
With mutable classes, you have to think about whether it gets modified.
A point of clarification, by my understanding, Python is pass by value just like Java and C (without modifiers). But what you are passing is usually a mutable object.
(Edit: almost all mainstream languages follow these semantics now. The most prominent exception is Lisp, where you can not only modify mutable objects, but reassign the value pointed to by a variable.)
这并不直接使您的代码片段更加清晰,但无论如何我想提一下:我们对参数使用命名约定来准确显示您想要的内容。 我们使用“in”、“out”和“io”前缀。 因此 DoSomething 声明看起来像 DoSomething(ioSomeObject inA)。 当在 Visual Studio 中使用 Visual Assist 时,您将看到一个弹出窗口,其中包含参数的类型和名称,并且其中记录了可能的副作用。 在我看来,这比记录后置条件更清晰。
问候,
塞巴斯蒂安
This doesn't directly make your code-snippet more clear, but I want to mention it anyway: we're using a naming convention for the parameters to display exactly what you want. We use 'in', 'out' and 'io' prefixes. So the DoSomething declaration would look like DoSomething(ioSomeObject inA). When working in Visual Studio with Visual Assist you'll get a popup with the types and names of the parameters, and this documents possible side-effects. In my opinion this is more clear than documenting post-conditions.
Regards,
Sebastiaan