是什么让 Scala 的运算符重载“好”,而 C++ 的“坏”?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1098303/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-22 01:31:26  来源:igfitidea点击:

What makes Scala's operator overloading "good", but C++'s "bad"?

c++scalaoperator-overloading

提问by skaffman

Operator overloading in C++ is considered by many to be A Bad Thing(tm), and a mistake not to be repeated in newer languages. Certainly, it was one feature specifically dropped when designing Java.

C++ 中的运算符重载被许多人认为是一件坏事(tm),并且是一个在新语言中不会重复的错误。当然,这是在设计 Java 时特别删除的一项功能。

Now that I've started reading up on Scala, I find that it has what looks very much like operator overloading (although technically it doesn't have operator overloading because it doesn't have operators, only functions). However, it wouldn't seem to be qualitatively different to the operator overloading in C++, where as I recall operators are defined as special functions.

现在我已经开始阅读 Scala,我发现它看起来很像运算符重载(尽管从技术上讲它没有运算符重载,因为它没有运算符,只有函数)。但是,它似乎与 C++ 中的运算符重载没有本质上的不同,我记得运算符在 C++ 中被定义为特殊函数。

So my question is what makes the idea of defining "+" in Scala a better idea than it was in C++?

所以我的问题是,是什么让在 Scala 中定义“+”的想法比在 C++ 中定义更好?

回答by James Iry

C++ inherits true blue operators from C. By that I mean that the "+" in 6 + 4 is very special. You can't, for instance, get a pointer to that + function.

C++ 从 C 继承了真正的蓝色运算符。我的意思是 6 + 4 中的“+”非常特殊。例如,您无法获得指向该 + 函数的指针。

Scala on the other hand doesn't have operators in that way. It just has great flexibility in defining method names plus a bit of built in precedence for non-word symbols. So technically Scala doesn't have operator overloading.

另一方面,Scala 没有那样的操作符。它只是在定义方法名称方面具有很大的灵活性,并为非单词符号提供了一些内置的优先级。所以从技术上讲,Scala 没有运算符重载。

Whatever you want to call it, operator overloading isn't inherently bad, even in C++. The problem is when bad programmers abuse it. But frankly, I'm of the opinion that taking away programmers ability to abuse operator overloading doesn't put a drop in the bucket of fixing all the things that programmers can abuse. The real answer is mentoring. http://james-iry.blogspot.com/2009/03/operator-overloading-ad-absurdum.html

无论您想怎么称呼它,运算符重载本质上都不是坏事,即使在 C++ 中也是如此。问题是当糟糕的程序员滥用它时。但坦率地说,我认为剥夺程序员滥用运算符重载的能力并不能解决程序员可能滥用的所有问题。真正的答案是指导。 http://james-iry.blogspot.com/2009/03/operator-overloading-ad-absurdum.html

None-the-less, there are differences between C++'s operator overloading and Scala's flexible method naming which, IMHO, make Scala both less abusable and more abusable.

尽管如此,C++ 的运算符重载和 Scala 灵活的方法命名之间存在差异,恕我直言,这使 Scala 既不易滥用又更易于滥用。

In C++ the only way to get in-fix notation is using operators. Otherwise you must use object.message(argument) or pointer->messsage(argument) or function(argument1, argument2). So if you want a certain DSLish style to your code then there's pressure to use operators.

在 C++ 中,获得固定符号的唯一方法是使用运算符。否则,您必须使用 object.message(argument) 或 pointer->message(argument) 或 function(argument1,argument2)。因此,如果您希望代码具有某种 DSLish 风格,那么使用运算符就会有压力。

In Scala you can get infix notation with any message send. "object message argument" is perfectly ok, which means you don't need to use non-word symbols just to get infix notation.

在 Scala 中,您可以通过任何消息发送获得中缀符号。“对象消息参数”是完全可以的,这意味着您不需要使用非单词符号来获得中缀符号。

C++ operator overloading is limited to essentially the C operators. Combined with the limitation that only operators may be used infix that puts pressure on people to try to map a wide range of unrelated concepts onto a relatively few symbols like "+" and ">>"

C++ 运算符重载本质上仅限于 C 运算符。结合只能使用运算符的限制,这给人们带来压力,试图将各种不相关的概念映射到相对较少的符号上,例如“+”和“>>”

Scala allows a huge range of valid non-word symbols as method names. For instance, I've got an embedded Prolog-ish DSL where you can write

Scala 允许使用大量有效的非单词符号作为方法名称。例如,我有一个嵌入式 Prolog-ish DSL,您可以在其中编写

female('jane)!         // jane is female
parent('jane,'john)!   // jane is john's parent
parent('jane, 'wendy)! // jane is wendy's parent

mother('Mother, 'Child) :- parent('Mother, 'Child) & female('Mother) //'// a mother of a child is the child's parent and is female

mother('X, 'john)?  // find john's mother
mother('jane, 'X)?  // find's all of jane's children

The :-, !, ?, and & symbols are defined as ordinary methods. In C++ only & would be valid so an attempt to map this DSL into C++ would require some symbols that already evoke very different concepts.

:-、!、? 和 & 符号被定义为普通方法。仅在 C++ 中 & 将是有效的,因此尝试将此 DSL 映射到 C++ 将需要一些已经引起非常不同概念的符号。

Of course, this also opens up Scala to another kind of abuse. In Scala you can name a method $!&^% if you want to.

当然,这也为 Scala 带来了另一种滥用。在 Scala 中,您可以根据需要命名方法 $!&^%。

For other languages that, like Scala, are flexible in the use of non-word function and method names see Smalltalk where, like Scala, every "operator" is just another method and Haskell which allows the programmer to define precedence and fixity of flexibly named functions.

对于其他语言,如 Scala,在使用非单词函数和方法名称方面很灵活,请参阅 Smalltalk,其中,像 Scala 一样,每个“运算符”只是另一种方法,而 Haskell 允许程序员定义灵活命名的优先级和固定性职能。

回答by skaffman

Operator overloading in C++ is considered by many to be A Bad Thing(tm)

许多人认为 C++ 中的运算符重载是一件坏事(tm)

Only by the ignorant. It is absolutely required in a language like C++, and it is noticeable that other languages that started off taking a "purist" view, have added it once their designers found out how necessary it is.

只为无知。它在像 C++ 这样的语言中是绝对需要的,值得注意的是,其他一开始采取“纯粹”观点的语言,一旦他们的设计者发现它是多么必要,就会添加它。

回答by Faisal Vali

Operator overloading was never universally thought to be a bad idea in C++ - just the abuse of operator overloading was thought to be a bad idea. One doesn't really need operator overloading in a language since they can be simulated with more verbose function calls anyway. Avoiding operator overloading in Java made the implementation and specification of Java a little simpler and it forced programmers to not abuse operators. There has been some debate in the Java community about introducing operator overloading.

在 C++ 中,运算符重载从未被普遍认为是一个坏主意——只是滥用运算符重载被认为是一个坏主意。一种语言中并不真正需要运算符重载,因为无论如何它们都可以用更详细的函数调用来模拟。避免 Java 中的运算符重载使 Java 的实现和规范更简单一些,并迫使程序员不要滥用运算符。Java 社区中一直存在一些关于引入运算符重载的争论。

The advantages and disadvantages of operator overloading in Scala are the same as in C++ - you can write more natural code if you use operator overloading appropriately - and more cryptic, obfuscated code if you don't.

Scala 中运算符重载的优缺点与 C++ 中的相同 - 如果您适当地使用运算符重载,您可以编写更自然的代码 - 如果您不使用运算符重载,则可以编写更神秘、混淆的代码。

FYI: Operators are not defined as special functions in C++, they behave just like any other function - although there are some differences in name lookup, whether they need to be member functions, and the fact that they can be called in two ways: 1) operator syntax, and 2) operator-function-id syntax.

仅供参考:运算符在 C++ 中并未定义为特殊函数,它们的行为与任何其他函数一样 - 尽管在名称查找、它们是否需要成为成员函数以及它们可以通过两种方式调用的事实方面存在一些差异:1 ) 运算符语法,以及 2) 运算符函数 ID 语法。

回答by jmanning2k

This article - "The Positive Legacy of C++ and Java" - answers your question directly.

这篇文章——“ C++ 和 Java 的积极遗产”——直接回答了你的问题。

"C++ has both stack allocation and heap allocation and you must overload your operators to handle all situations and not cause memory leaks. Difficult indeed. Java, however, has a single storage allocation mechanism and a garbage collector, which makes operator overloading trivial" ...

“C++ 有栈分配和堆分配,你必须重载你的操作符来处理所有情况,而不是导致内存泄漏。确实很难。然而,Java 有一个单一的存储分配机制和一个垃圾收集器,这使得操作符重载变得微不足道”。 ..

Java mistakenly (according to the author) omitted operator overloading because it was complicated in C++, but forgot why (or didn't realize that it didn't apply to Java).

Java 错误地(根据作者的说法)省略了运算符重载,因为它在 C++ 中很复杂,但忘记了原因(或者没有意识到它不适用于 Java)。

Thankfully, higher level languages like Scala give developers options, while still running on the same JVM.

值得庆幸的是,像 Scala 这样的高级语言为开发人员提供了选择,同时仍然在同一个 JVM 上运行。

回答by dan04

There is nothing wrong with operator overloading. In fact, there's something wrong with nothaving operator overloading for numeric types. (Take a look at some Java code that uses BigInteger and BigDecimal.)

运算符重载没有任何问题。事实上,还有一些错误具有运算符重载数字类型。(看看一些使用 BigInteger 和 BigDecimal 的 Java 代码。)

C++ has a tradition of abusing the feature, though. An often-cited example is that the bitshift operators are overloaded to do I/O.

不过,C++ 有滥用该功能的传统。一个经常被引用的例子是移位运算符被重载来执行 I/O。

回答by dan04

Operator overloading is not something that you really "need" very often, but when using Java, if you hit a point where you genuinely need it, it'll make you want to rip your fingernails out just so you have an excuse to stop typing.

运算符重载并不是你真正“经常需要”的东西,但是在使用 Java 时,如果你真的需要它,它会让你想撕掉你的指甲,这样你就有了停止打字的借口.

That code which you've just found overflows a long? Yup, you're going to have to retype the whole lot to make it work with BigInteger. There is nothing more frustrating that having to reinvent the wheel just to change the type of a variable.

你刚刚发现的那段代码溢出了很长时间?是的,您将不得不重新输入全部内容才能使其与 BigInteger 一起使用。没有什么比仅仅为了改变变量的类型而重新发明轮子更令人沮丧的了。

回答by Martin York

In general it is not a bad thing.
New languages such as C# also have operator overloading.

一般来说,这不是一件坏事。
C# 等新语言也有运算符重载。

It is the abuse of operator overloading that is a bad thing.

滥用运算符重载是一件坏事。

But there are also problems with operator overloading as defined in C++. Because overloaded operators are just syntactic sugar for method calls they behave just like method. On the other hand normal built-in operators do not behave like methods. These inconsistency can be cause problems.

但是 C++ 中定义的运算符重载也存在问题。因为重载运算符只是方法调用的语法糖,所以它们的行为就像方法一样。另一方面,普通的内置运算符的行为不像方法。这些不一致可能会导致问题。

Off the top of my head operators ||and &&.
The built in versions of these are short-cut operators. This is not true for overloaded versions and has caused some problems.

关闭我的头脑运营商||&&.
这些的内置版本是快捷操作符。对于重载的版本,情况并非如此,并导致了一些问题。

The fact that + - * / all return the same type that they operate on (after operator promotion)
The overloaded versions can return anything (This is where the abuse sets in, If your operators start to return some arbitrator type the user was not expecting things go down hill).

+ - * / 都返回它们操作的相同类型的事实(在运算符提升之后)
重载版本可以返回任何东西(这就是滥用的地方,如果您的运算符开始返回用户不期望的某些仲裁类型事情走下坡路)。

回答by Blaisorblade

Guy Steele argued that operator overloading should be in Java as well, in his keynote speech "Growing a language" - there's a video and a transcription of it, and it's really an amazing speech. You will wonder what he is talking about for the first couple of pages, but if you keep on reading, you will see the point and achieve enlightenment. And the very fact that he could do such a speech at all is also amazing.

Guy Steele 认为运算符重载也应该在 Java 中出现,在他的主题演讲“发展一种语言”中 - 有一个视频和它的转录,这真的是一个了不起的演讲。在前几页中,您会想知道他在说什么,但如果您继续阅读,您就会明白这一点并获得启蒙。而他竟然能发表这样的演讲,也是非常了不起的。

At the same time, this talk inspired a lot of fundamental research, probably including Scala - it's one of those papers that everybody should read to work in the field.

与此同时,这次演讲激发了许多基础研究,可能包括 Scala——这是每个人都应该阅读的论文之一,以便在该领域工作。

Back to the point, his examples are mostly about numeric classes (like BigInteger, and some weirder stuff), but that's not essential.

回到正题,他的例子主要是关于数字类(比如 BigInteger 和一些更奇怪的东西),但这不是必需的。

It is true, though, that misuse of operator overloading can lead to terrible results, and that even proper uses can complicate matters, if you try to read code without studying a bit the libraries it uses. But is that a good idea? OTOH, shouldn't such libraries try to include an operator cheat sheet for their operators?

但是,如果您尝试阅读代码而不研究它使用的库,那么滥用运算符重载会导致可怕的结果,即使正确使用也会使问题复杂化。但这是个好主意吗?OTOH,这样的库不应该尝试为他们的操作员包含一个操作员备忘单吗?

回答by Saem

I believe EVERY answer missed this. In C++ you can overload operators all you want, but you can't effect the precedence with which they're evaluated. Scala doesn't have this issue, IIRC.

我相信每个答案都错过了这一点。在 C++ 中,您可以随心所欲地重载运算符,但不能影响它们的计算优先级。Scala 没有这个问题,IIRC。

As for it being a bad idea, besides precedence issues, people come up with really daft meanings for operators, and it rarely aids readability. Scala libraries are especially bad for this, goofy symbols that you must memorize each time, with library maintainers sticking their heads in the sand saying, 'you only need to learn it once'. Great, now I need to learn some 'clever' author's cryptic syntax * the number of libraries I care to use. It wouldn't be so bad if there existed a convention of ALWAYS supplying a literate version of the operators.

至于这是一个坏主意,除了优先级问题之外,人们还为操作符提出了非常愚蠢的含义,而且很少有助于可读性。Scala 库在这方面尤其糟糕,你每次都必须记住这些愚蠢的符号,库维护者把头埋在沙子里说,“你只需要学习一次”。太好了,现在我需要学习一些“聪明”作者的神秘语法 * 我想使用的库数量。如果存在始终提供运算符的文字版本的约定,那就不会那么糟糕了。

回答by Joshua

The only thing known wrong in C++ is the lack of the ability to overload []= as a separate operator. This could be hard to implement in a C++ compiler for what is probably not an obvious reason but plenty worth it.

C++ 中唯一已知的错误是缺乏将 []= 作为单独的运算符重载的能力。这可能很难在 C++ 编译器中实现,这可能不是一个明显的原因,但非常值得。