运算符重载——禁止真的合理吗?
Java 禁止运算符重载,但来自 C++,我看不出有任何理由这样做。在运算符符号与其他符号一样的语言中,相同的规则适用于“+”和“加号”,并且没有问题。那么有什么意义呢?
编辑:更具体地说,请告诉我重载“+”的缺点可能会过度重载“等于”。
Java forbids operator overloading, but coming from C++ I do not see any reason for that. In languages where operator symbols are symbols as any other, same rules apply to "+" as to"plus" and there is no problem. So what is the point?
Edit: To be more concrete, show me which disadvantage overloaded "+" may have over overloaded "equals".
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
要点是,例如,每当您看到代码中使用加号时,只要您知道其操作数的类型(您在 Java 中总是这样做,因为它是强类型的),您就可以准确地知道它的作用。
The point is that whenever you see, for example, a plus sign being used in the code, you know exactly what it does given that you know the types of its operands (which you always do in Java, as it is strongly typed).
就像 Java 中的许多其他东西一样,这是一个限制,因为如果使用不当可能会造成混乱。 (类似于指针算术被禁止,因为它容易出错。)我是 Java 的忠实粉丝,但我通常认为不应该仅仅因为它可能就禁止它滥用。
例如,BigInteger 将从重载 + 运算符中受益匪浅。
Just as many other things in Java, this is a restriction because it may be confusing if used improperly. (Similarly as pointer arithmetic is forbidden because it is error prone.) I'm a big fan of Java, but I'm generally of the opinion that it shouldn't be forbidden just because it could be misused.
For instance, BigInteger would benefit greatly from overloading the + operator.
好吧,我会尝试一下,假设 Gabriel Ščerbák 这样做的原因比反对一种语言更好。
对我来说,问题之一是可管理的复杂性:我面前的代码有多少是我必须解码的,而不是简单阅读的?
在大多数传统语言中,当看到表达式
a + b
时,我就知道会发生什么。变量a
和b
将被添加到一起。我非常有信心,在幕后,代码将是非常简洁、非常快速的本机机器代码,它将两个数字相加,无论数字是短整数、双精度还是两者的某种混合。 我可能还必须假设这些可能是连接的字符串,但这是对一个完全不同的问题的咆哮 - 但如果你从正确的角度观察它,就会对这个咆哮进行调味。)(在某些语言中, 自己的用户定义类型——比如无所不在的 Complex 类型(以及为什么 Complex 不是现代语言中的标准数据类型,这是我无法理解的,但这又是对不同的问题)——如果我重载一个运算符(或者更确切地说,如果该运算符对我来说重载了——比如说,我正在使用一个库),如果没有仔细观察代码,我将不知道我在现在在对象上调用(可能是虚拟的)方法,而不是在幕后为我生成非常紧凑、简洁的代码。我不会知道隐藏的转换、隐藏的临时变量、……嗯,编写许多运算符所涉及的一切。为了找出代码中到底发生了什么,我必须非常密切地关注每一行,并跟踪可能距离代码中当前位置三个屏幕的声明。说这阻碍了我对眼前代码的理解是轻描淡写的。重要的细节正在丢失,因为语法糖让东西变得太美味了。
当我被迫在对象上使用显式方法(甚至是适用的静态方法或全局方法)时,这对我来说是一个信号,在我阅读时,它告诉我潜在的成本开销和瓶颈等。我知道,甚至不用想一瞬间,我正在处理一个方法,我有调度开销,我可能有临时对象创建和删除开销,等等。一切都是就在我眼前——或者至少有足够的指标在我面前,我知道要更加小心。
我本质上并不反对运算符重载。有时它会使代码更清晰,确实如此,尤其是当您对许多令人困惑的表达式进行复杂的计算时。然而,我可以理解为什么有人可能不想将其放入他们的语言中。
从语言设计者的角度来看,还有一个不喜欢运算符重载的进一步原因。运算符重载会导致语法非常非常困难。 C++ 已经因几乎不可解析而臭名昭著,它的一些构造(例如运算符重载)是造成这种情况的原因。同样,从编写该语言的人的角度来看,我完全可以理解为什么运算符重载被视为一个坏主意(或者是一个在实现中很糟糕的好主意)。
(当然,除了您已经拒绝的其他原因之外,这就是全部。我将在我过去的 C++ 岁月里提交我自己的
operator-,()
重载,只是为了真的很烦人。)OK, I'll try my hand at this under the assumption that Gabriel Ščerbák is doing this for better reasons than railing against a language.
The issue for me is one of manageable complexity: How much of the code in front of me do I have to decode vs. simply read?
In most conventional languages, upon seeing the expression
a + b
I know what is going to happen. The variablesa
andb
will be added together. I'm pretty confident that behind the scenes the code will be very concise, very fast native machine code that adds the two numbers, whether the numbers are short integers or double-precision or some mixture of the two. (In some languages I may have to also assume that these could be strings being concatenated, but that's a rant for an entirely different question -- but one that flavours this rant if you peer at it from the right angle.)When I make my own user-defined type -- say the omnipresent Complex type (and why Complex isn't a standard data type in modern languages is way the Hell beyond me, but that, again, is a rant for a different question) -- if I overload an operator (or, rather, if the operator is overloaded for me -- I'm using a library, say), short of peering very closely at the code I will not know that I'm now calling (possibly-virtual) methods on objects instead of having very tight, concise code generated for me behind the scenes. I will not know of the hidden conversions, the hidden temporary variables, the ... well, everything that goes along with writing many operators. To find out what's really going on in my code I have to pay very close attention to every line and keep track of declarations that may be three screens away from my current location in the code. To say that this impedes my understanding of the code flowing before my eyes is an understatement. Important details are being lost because the syntactic sugar is making things taste too tasty.
When I'm forced to use explicit methods on the objects (or even static methods or global methods where that applies) this is a signal to me, while I'm reading, that tells me of the potential cost overheads and bottlenecks and the like. I know, without even having to think for an instant, that I'm dealing with a method, that I've got dispatching overhead, that I may have temporary object creation and deletion overhead, etc. Everything's in front of me right before my eyes -- or at least enough indicators are in front of me that I know to be more careful.
I'm not intrinsically opposed to operator overloading. There are times when it makes code clearer, yes indeed, especially when you have complicated calculations over many baffling expressions. I can understand, however, exactly why someone might not want to put that into their language.
There is a further reason not to like operator overloading from the language designer's viewpoint. Operator overloading makes for very, very, very difficult grammars. C++ is already infamous for being nigh-unparseable and some of its constructs, like operator overloading, are the cause of it. Again from the viewpoint of someone writing the language I can fully understand why operator overloading was left off as a bad idea (or a good idea that's bad in implementation).
(This is all, of course, in addition to the other reasons you've already rejected. I'll submit my own overloading of
operator-,()
in my old C++ days in that stew just to be really annoying.)运算符重载本身没有问题,但它实际上是如何被使用的。只要你重载运算符使其有意义,语言仍然有意义,但如果你赋予运算符其他含义,就会使语言不一致。
(一个例子是左移 (<<) 和右移 (>>) 运算符如何在 C++ 中重载以表示“输入”和“输出”...)
因此,省略运算符时的推理超载可能是误用的风险大于操作员超载的好处。
There is no problem with operator overloading itself, but how it's actually has been used. As long as you overload the operators to make sense, the language still makes sense, but if you give other meanings to operators, it makes the language inconsistent.
(One example is how the shift left (<<) and shift right (>>) operators has been overloaded in C++ to mean "input" and "output"...)
So, the reasoning when leaving out operator overloading was probably that the risk of misuse was greater than the benefits of having operator overloading.
我认为 Java 将通过扩展其运算符来覆盖内置的 Number 对象类型而受益匪浅。据说 Java 的早期(1.0 之前)版本就拥有它(因为没有原语 - 一切都是对象),但当时的 VM 技术使其从性能角度来看令人望而却步。
但就允许用户定义的运算符重载而言,它通常不符合 Java 语言的精神。主要问题很简单,很难实现一个与跨对象类型的数学期望一致的运算符,并且它将为许多糟糕的实现打开大门,从而导致很难找到(因此昂贵)错误。您只需查看一般 Java 代码中有多少错误的 equals 实现(如违反约定),问题只会变得更糟。
当然,有些语言优先考虑功能和语法美感,而不是这些问题,并且赋予它们更多的功能。它只是不是Java。
编辑:自定义
+
运算符与自定义==
实现(在 Java 中的equals(Object)
方法中捕获)有何不同?事实并非如此。只是由于允许操作符重载,对于六年级学生来说直观的事情变得不真实了。equals(Object)
实现的现实经验表明,如此复杂的契约在现实世界中如何变得难以执行。进一步编辑:让我澄清一下上面的内容,因为我在编辑时缩短了它并失去了重点。数学中的
+
运算符具有某些属性,其中之一是两边数字的出现顺序并不重要 - 它具有相同的结果。因此,考虑一下+
向集合执行添加的最简单情况:对
+
的直观理解会导致a + b
的预期> 或b + a
会给出相同的结果,但它们当然不会。开始混合两种对象类型,在其 plus 方法中将彼此作为参数(例如 Collection 和 String),事情会变得更难以理解。现在当然可以在易于理解的对象上设计运算符,并产生比没有它们更好、更易读和更容易理解的代码。但关键是,在本土企业 API 中,您最终看到的往往是混淆的代码。
I think that Java would benefit greatly from extending its operators to cover built-in Number object types. Early (pre-1.0) versions of Java were said to have it (in that there were no primitives - everything was an object) but the VM technology of the time made it prohibitive from a performance view.
But in terms of in general allowing user defined operator overloading, it is not in the spirit of the Java language. The main problem is simply that it is hard to implement an operator that is consistent with what you expect from mathematics across object types and it will open the door to a lot of bad implementations which lead to a lot of hard to find (therefore expensive) bugs. You can just look at how many bad equals implementations (as in violate the contract) there are in general Java code, and the problem would only get worse from there.
Of course there are languages that prioritize power and syntactical beauty over such concerns, and more power to them. It is just not Java.
Edit: How is a custom
+
operator different than a custom==
implementation (captured in Java in theequals(Object)
method)? It isn't, really. It is just that by allowing operator overloading, things that are intuitive to a sixth grader become untrue. The real world experience ofequals(Object)
implementations shows how such complex contracts become hard to enforce in the real world.Further Edit: Let me clarify the above, as I shortened it while editing and lost the point. A
+
operator in math has certain properties, one of which is that it doesn't matter which order the numbers on either side appear - it has the same result. So consider even the simplest case of a+
performing an add to a Collection:The intuitive understanding of
+
would lead to an expectation thata + b
orb + a
would give the same result, but of course they would not. Start mixing two object types that take each other as paramaters in their plus method (say Collection and String) and things get harder to follow.Now certainly it is possible to design operators on objects which are well understood and lead to better, more readable and more understandable code than without them. But the point is that more often than not in home-grown corporate APIs what you would end up seeing is obfuscated code.
存在一些问题:
但即使完全禁止,你也不能总是保护白痴免受他们自己的侵害。
There are a few problems:
But you can't always protect idiots from themselves even with an outright ban.