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
:-、!、? 和 & 符号被定义为普通方法。 仅在 C++ 中 & 是有效的,因此尝试将此 DSL 映射到 C++ 将需要一些已经引发非常不同概念的符号。
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.
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.
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
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.
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.
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.
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 ">>"
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
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.
Of course, this also opens up Scala to another kind of abuse. In Scala you can name a method $!&^% if you want to.
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.
只有无知的人才能做到。 在像 C++ 这样的语言中,它是绝对必需的,并且值得注意的是,其他一开始采取“纯粹主义”观点的语言,一旦其设计者发现它有多么必要,就添加了它。
Operator overloading in C++ is considered by many to be A Bad Thing(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.
Scala 中运算符重载的优点和缺点与 C++ 中的相同 - 如果正确使用运算符重载,你可以编写更自然的代码 - 如果不使用运算符重载,你会编写更神秘、混乱的代码。
仅供参考:运算符在 C++ 中没有被定义为特殊函数,它们的行为就像任何其他函数一样 - 尽管在名称查找、它们是否需要是成员函数以及它们可以通过两种方式调用方面存在一些差异:1 ) 运算符语法,以及 2) 运算符-函数-id 语法。
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.
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.
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++ 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" ...
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).
Thankfully, higher level languages like Scala give developers options, while still running on the same JVM.
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.
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.
There is nothing wrong with operator overloading. In fact, there's something wrong with not having operator overloading for numeric types. (Take a look at some Java code that uses BigInteger and BigDecimal.)
C++ has a tradition of abusing the feature, though. An often-cited example is that the bitshift operators are overloaded to do I/O.
In general it is not a bad thing. New languages such as C# also have operator overloading.
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.
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).
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.
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.
Back to the point, his examples are mostly about numeric classes (like BigInteger, and some weirder stuff), but that's not essential.
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?
C++ 中唯一已知的错误是缺乏将 []= 重载为单独运算符的能力。 这可能很难在 C++ 编译器中实现,原因可能不是显而易见,但很值得。
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.
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.
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.
As the other answers have pointed out; operator overloading itself isn't necessarily bad. What is bad it when it is used in ways that make the resulting code un-obvious. Generally when using them you need to make them do the least surprising thing (having operator+ do division would cause trouble for a rational class's usage) or as Scott Meyers says:
Clients already know how types like int behave, so you should strive to have your types behave in the same way whenever reasonable... When in doubt, do as the ints do. (From Effective C++ 3rd Edition item 18)
Now some people have taken operator overloading to the extreme with things like boost::spirit. At this level you have no idea how it is implemented but it makes an interesting syntax to get what you want done. I'm not sure if this is good or bad. It seems nice, but I haven't used it.
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.
AFAIK, There is nothing special in operator functions compared to "normal" member functions. Of course you only have a certain set of operators that you can overload, but that doesn't make them very special.
发布评论
评论(14)
C++ 从 C 继承了真正的蓝色运算符。我的意思是 6 + 4 中的“+”非常特殊。 例如,您无法获取指向该 + 函数的指针。
另一方面,Scala 没有这样的运算符。 它只是在定义方法名称方面具有很大的灵活性,并且为非单词符号提供了一些内置的优先级。 所以从技术上讲,Scala 没有运算符重载。
无论你想怎么称呼它,运算符重载本质上并不是坏事,即使在 C++ 中也是如此。 问题是当糟糕的程序员滥用它时。 但坦率地说,我认为剥夺程序员滥用运算符重载的能力并不会降低解决程序员可能滥用的所有问题的能力。 真正的答案是指导。 http://james-iry.blogspot.com/2009 /03/operator-overloading-ad-absurdum.html
尽管如此,C++ 的运算符重载和 Scala 灵活的方法命名之间存在差异,恕我直言,这使得 Scala 既不那么容易被滥用,又更容易被滥用。
在 C++ 中,获得固定表示法的唯一方法是使用运算符。 否则,您必须使用 object.message(argument) 或指针->messsage(argument) 或 function(argument1, argument2)。 因此,如果您希望代码具有某种 DSish 风格,那么使用运算符就有压力。
在 Scala 中,您可以在发送的任何消息中使用中缀表示法。 “对象消息参数”完全没问题,这意味着您不需要使用非单词符号来获得中缀表示法。
C++ 运算符重载本质上仅限于 C 运算符。 再加上只能使用中缀运算符的限制,这给人们带来了压力,要求他们尝试将各种不相关的概念映射到相对较少的符号(例如“+”和“>>”)上。
Scala 允许使用大量有效的非单词符号作为方法名称。 例如,我有一个嵌入式 Prolog-ish DSL,您可以在其中编写
:-、!、? 和 & 符号被定义为普通方法。 仅在 C++ 中 & 是有效的,因此尝试将此 DSL 映射到 C++ 将需要一些已经引发非常不同概念的符号。
当然,这也让 Scala 面临另一种滥用。 在 Scala 中,如果您愿意,您可以命名一个方法 $!&^%。
对于其他语言,如 Scala,可以灵活使用非单词函数和方法名称,请参见 Smalltalk,其中如 Scala,每个“运算符”只是另一个方法,而 Haskell 允许程序员定义灵活命名的优先级和固定性功能。
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.
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.
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
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.
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.
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.
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 ">>"
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
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.
Of course, this also opens up Scala to another kind of abuse. In Scala you can name a method $!&^% if you want to.
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.
只有无知的人才能做到。 在像 C++ 这样的语言中,它是绝对必需的,并且值得注意的是,其他一开始采取“纯粹主义”观点的语言,一旦其设计者发现它有多么必要,就添加了它。
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++ 中,运算符重载从来没有被普遍认为是一个坏主意——只是滥用运算符重载被认为是一个坏主意。 人们实际上并不需要语言中的运算符重载,因为无论如何都可以使用更详细的函数调用来模拟它们。 避免 Java 中的运算符重载使得 Java 的实现和规范变得更加简单,并且迫使程序员不要滥用运算符。 Java 社区中对于引入运算符重载存在一些争论。
Scala 中运算符重载的优点和缺点与 C++ 中的相同 - 如果正确使用运算符重载,你可以编写更自然的代码 - 如果不使用运算符重载,你会编写更神秘、混乱的代码。
仅供参考:运算符在 C++ 中没有被定义为特殊函数,它们的行为就像任何其他函数一样 - 尽管在名称查找、它们是否需要是成员函数以及它们可以通过两种方式调用方面存在一些差异:1 ) 运算符语法,以及 2) 运算符-函数-id 语法。
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.
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.
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++ 和 Java 的积极遗产” - 回答了您的问题直接提问。
Java 错误地(根据作者的说法)省略了运算符重载,因为它在 C++ 中很复杂,但忘记了原因(或者没有意识到它不适用于 Java)。
值得庆幸的是,像 Scala 这样的高级语言为开发人员提供了选择,同时仍然在相同的 JVM 上运行。
This article - "The Positive Legacy of C++ and Java" - answers your question directly.
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).
Thankfully, higher level languages like Scala give developers options, while still running on the same JVM.
运算符重载并不是您经常“需要”的东西,但是在使用 Java 时,如果您真正需要它,它会让您想撕掉指甲,这样您就有借口停止打字。
您刚刚发现的代码溢出很长? 是的,您必须重新输入全部内容才能使其与 BigInteger 一起使用。 没有什么比仅仅为了改变变量的类型而重新发明轮子更令人沮丧的了。
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.
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 和 BigDecimal 的 Java 代码。)
不过,C++ 有滥用该功能的传统。 一个经常被引用的例子是移位运算符被重载以执行 I/O。
There is nothing wrong with operator overloading. In fact, there's something wrong with not having operator overloading for numeric types. (Take a look at some Java code that uses BigInteger and BigDecimal.)
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# 等新语言也有运算符重载。
滥用运算符重载是一件坏事。
但 C++ 中定义的运算符重载也存在问题。 因为重载运算符只是方法调用的语法糖,所以它们的行为就像方法一样。 另一方面,普通的内置运算符的行为与方法不同。 这些不一致可能会导致问题。
我突然想到运算符
||
和&&
。这些的内置版本是快捷运算符。 对于重载版本来说情况并非如此,并导致了一些问题。
事实上 + - * / 都返回它们所操作的相同类型(在运算符提升之后)
重载的版本可以返回任何内容(这就是滥用的地方,如果您的操作员开始返回某些仲裁器类型,则用户不会期望事情会走下坡路)。
In general it is not a bad thing.
New languages such as C# also have operator overloading.
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.
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).
Guy Steele 在他的主题演讲“发展一门语言”中认为,Java 中也应该存在运算符重载 - 有一个视频和转录,这确实是一次令人惊叹的演讲。 你可能会想知道他在前几页里在说什么,但如果你继续读下去,你就会明白要点并获得启发。 他能发表这样的演讲本身也令人惊叹。
同时,这次演讲激发了许多基础研究,可能包括 Scala——这是每个人在该领域工作都应该阅读的论文之一。
回到正题,他的示例主要是关于数字类(例如 BigInteger 和一些更奇怪的东西),但这不是必需的。
不过,确实,滥用运算符重载可能会导致可怕的结果,并且如果您尝试阅读代码而不研究它所使用的库,那么即使正确使用也会使问题变得复杂。 但这是个好主意吗? OTOH,这样的库不应该尝试为其操作员提供操作员备忘单吗?
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.
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.
Back to the point, his examples are mostly about numeric classes (like BigInteger, and some weirder stuff), but that's not essential.
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?
C++ 中唯一已知的错误是缺乏将 []= 重载为单独运算符的能力。 这可能很难在 C++ 编译器中实现,原因可能不是显而易见,但很值得。
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++ 的发明 - 它来自 Algol IIRC,甚至 Gosling 也不认为这是一个坏主意。
Operator overloading was not a C++ invention - it came from Algol IIRC and even Gosling does not claim it is a bad idea in general.
我相信每个答案都忽略了这一点。 在 C++ 中,您可以根据需要重载运算符,但无法影响它们求值的优先级。 Scala 没有这个问题,IIRC。
至于这是一个坏主意,除了优先级问题之外,人们还为运算符提出了非常愚蠢的含义,并且它很少有助于可读性。 Scala 库在这方面尤其糟糕,你每次都必须记住那些愚蠢的符号,库维护者把头埋在沙子里说,“你只需要学一次”。 太好了,现在我需要学习一些“聪明”作者的神秘语法*我喜欢使用的库的数量。 如果存在始终提供运算符的读写版本的约定,那就不会那么糟糕了。
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.
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.
正如其他答案所指出的; 运算符重载本身并不一定是坏事。 当它的使用方式使得生成的代码不明显时,这有什么不好的。 一般来说,在使用它们时,你需要让它们做最不令人惊讶的事情(让运算符+做除法会给理性类的使用带来麻烦)或者正如斯科特·迈耶斯(Scott Meyers)所说:
现在有些人已经将运算符重载发挥到了极致,比如 boost::spirit。 在这个级别,您不知道它是如何实现的,但它提供了一个有趣的语法来完成您想要的事情。 我不确定这是好是坏。 看起来不错,不过我没用过。
As the other answers have pointed out; operator overloading itself isn't necessarily bad. What is bad it when it is used in ways that make the resulting code un-obvious. Generally when using them you need to make them do the least surprising thing (having operator+ do division would cause trouble for a rational class's usage) or as Scott Meyers says:
Now some people have taken operator overloading to the extreme with things like boost::spirit. At this level you have no idea how it is implemented but it makes an interesting syntax to get what you want done. I'm not sure if this is good or bad. It seems nice, but I haven't used it.
我从未见过一篇文章声称 C++ 的运算符重载不好。
用户可定义的运算符使该语言的用户能够更轻松地获得更高水平的表达性和可用性。
I have never seen an article claiming that C++'s operator overloading is bad.
User-definable operators permit an easier higher level of expressivity and usability for users of the language.
AFAIK,与“普通”成员函数相比,运算符函数没有什么特别的。 当然,您只有一组可以重载的运算符,但这并不意味着它们非常特别。
AFAIK, There is nothing special in operator functions compared to "normal" member functions. Of course you only have a certain set of operators that you can overload, but that doesn't make them very special.