Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the root of the distinction in the meaning of equality between C++ and Python? [closed]

Tags:

c++

python

There appears to be an almost philosophical difference in the meaning of "equality" between C++ and Python. I became aware of this distinction through an attempt to do in Python something that is quite difficult in C++: distinguishing between two enum types when they are both just a wrapper for a set of integers, but the issue is broader than enums, hence the present question.

If I write in C++ code such as the following

#include <iostream>

struct Foo {
    bool operator==(const Foo& foo) const { return this == &foo; }
};

struct Bar {};

int main() {
    Foo foo = Foo();
    Bar bar = Bar();
    if (foo == bar) std::cout << "ok" << std::endl;
}

I fully expect that the equality comparison will fail. Indeed, it's a compilation error. You can't even compare two objects unless they're, just to get going, of the same type.

And yet it appears that "there is little (no?) precedent in Python for equality comparisons raising errors".

and "if [an object] raises every time it is compared to a [object of a different type], it will break any container it is added to".

Indeed, writing

class Foo(object):
    pass


class Bar(object):
    pass


foo = Foo()
bar = Bar()

if (foo == bar):
    print("equal")

reveals that there is no problem in comparing objects that should otherwise be incomparable.

What, philosophically, is the root of this distinction in the meaning of equality between the two languages?

Update

Part of my puzzlement at finding this out about Python is that so far every feature appears to have been designed with the intent of being "natural", "intuitive", even "human"—not that these can be defined in the first place.

But consider that you are at the fruit section of a grocery shop and ask one of the aproned chaps: "Could you tell me whether these oranges are Fuji or Red Delicious?" Surely no one could make sense of the question to venture an answer one way or the other. So the question is how to provide a response of "incredulous" in bits and bytes.

Update 2

(Too long to be a comment to @GiacomoAlzetta's comment) I respect your opinion. Still, from this point on, I will not respect a book on Python that does not dedicate a chapter, or at least a section, to pointing out that 3 < [1] is True, and that explains the background (whether historical or philosophical) for this. Being dynamically typed does not mean that one is so very cornered (because, e.g., one has only a handful of available names 'a', 'b', and 'c') to reuse a name for a very different meaning. Ultimately, it's not even a philosophical, but an engineering, issue: How do you remove, or at least reduce, the chance that one among multiple people collaborating on a software project will introduce bugs in the system? Bugs that remain dormant (because the language is dynamically typed—and we cannot predict computation paths) are far worse than bugs that scream "error".

like image 424
Calaf Avatar asked Mar 02 '18 03:03

Calaf


Video Answer


1 Answers

The fundamental intent in Python has changed over time. At the start, and until late in the development of Python 2, it was essentially the case that any two objects could be compared. Even mixed-type comparisons that made no intuitive sense, like:

>>> 3 < [1]
True

In cases like that, it was actually the string names of the types that were compared, and the result above was due to that, as strings, "int" < "list". This was driven mostly by a misguided (in hindsight) attempt to impose a total ordering on all objects.

Looking ahead to Python 3, the intent changed, and started to be implemented with the datetime module types (which were introduced in Python 2): mixed-typed <, <=, >, and >= comparisons that made scant intuitive sense were to raise exceptions instead, while senseless mixed-type == would always return False and senseless mixed-type != always True.

>>> import datetime
>>> n = datetime.datetime.now()
>>> n < 3
Traceback (most recent call last):
  ...
TypeError: can't compare datetime.datetime to int
>>> n >= 3
Traceback (most recent call last):
  ...
TypeError: can't compare datetime.datetime to int
>>> n == 3
False
>>> n != 3
True

Python 3 strives to act "like that" generally. Of course there are exceptions. For example, when comparing objects of different numeric types (like integers and floats), they're usually coerced to a common type under the covers.

I was deeply involved in these decisions (and wrote the datetime module), so you can trust me on that. But as to what C++ intends, you'll have to ask someone else ;-)

A Bit More Info

I should add that, up until the introduction of "rich comparisons" in Python 2, all comparisons funneled through a cmp() protocol: in the CPython implementation, comparing two objects returned one of the integers in [-1, 0, 1]. __cmp__() methods had no idea which of <, <=, ==, !=, >, and >= was actually desired. So while the "compare any two things no matter what" original design was disliked early on, it was technically difficult to get away from before rich comparisons were incorporated into the language. Then it became straightforward (if tedious).

like image 71
Tim Peters Avatar answered Sep 19 '22 16:09

Tim Peters