Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Could operator overloading have worked without references?

According to Bjarne Stroustrup, references were introduced into C++ to support operator overloading:

References were introduced primarily to support operator overloading.

C passes every function argument by value, and where passing an object by value would be inefficient or inappropriate the user can pass a pointer. This strategy doesn't work where operator overloading is used. In that case, notational convenience is essential because users cannot be expected to insert address-of operators if the objects are large. For example:

a = b - c;

is acceptable (that is, conventional) notation, but

a = &b - &c;

is not. Anyway, &b - &c already has a meaning in C, and I didn't want to change that.

Having both pointers and references in the language is a constant source of confusion for C++ novices.

Couldn't Bjarne have solved this problem by introducing a special language rule that allowed object arguments to decay into pointers if a user-defined operator function exists that takes such pointers?

The declaration and usage of subtraction would then have looked like:

Foo operator-(const Foo* x, const Foo* y);
a = b - c;

Was such a solution ever proposed/considered? Would there be any serious downsides to it?

Yes I know, references provide other advantages due to their restrictions, but that's not the point.

Interestingly, the assignment operator of C with classes seems to have worked exactly like that:

Changing the meaning of assignment for objects of a class [...] is done by declaring a class member function called operator=. For example:

class x {
public:
    int a;
    class y * p;
    void operator = (class x *);
};
like image 782
fredoverflow Avatar asked Nov 04 '11 10:11

fredoverflow


2 Answers

IME, automatic conversion is the bane of C++. Let's all write thankful emails to Bjarne Stroustrup for not adding a wide-sweeping automatic conversion from object to pointer.

If you look for a technical reason: In C++, the subtraction of pointers, even of pointers to user-defined types, is already well-defined. Also, this would lead to ambiguities with overloaded versions of operators that take objects per copy.

like image 162
sbi Avatar answered Sep 18 '22 03:09

sbi


I don't see how this solves the problem: operator- called on pointers already has a meaning.

You'd be defining an operator- for Foo* arguments, but that already exists.

Then you'd need some contrived semantics that "when called explicitly with pointers, the pointer arithmetic operator is called. When called with object lvalues, they decay into pointers, and then the overloaded version is called". Which, to be honest, seems far more contrived, and much less intuitive than just adding references.

And then inside the operator-, I get the arguments as pointers, and then I'd better make sure to dereference those if I need to call another (or the same) operator from there. Otherwise I'd accidentally end up performing pointer arithmetics.

You're proposing an implicit conversion which has different semantics than doing the conversion yourself. That is:

Foo foo;
bar(foo); 

performs an implicit conversion from Foo to Foo*, and then a function with the signature void bar(Foo*) is called.

But this code would do something completely different:

Foo foo;
bar(&foo);

that would also convert to a Foo*, and it would also call a function with the signature void bar(Foo*), but it would potentially be a different function. (In the case of operator-, for example, one would be the user-overloaded operator, and the other would be the standard pointer arithmetic one.

And then consider template code. In general, implicit conversions make templates really painful because the type passed in might not be the type you want to operate on.

Of course, there are more practical problems too:

References enable optimizations that aren't possible with pointers. (The compiler can assume they're never null, and it may be better able to do aliasing analysis)

Moreover, code would fail silently if no matching operator- can be found. Instead of telling me that, the compiler would implicitly start doing pointer arithmetics. Not a deal-breaker, but I really really prefer errors to be caught early where possible.

And one of the goals with C++ was to make it generic: to avoid having "magic" types or functions. In real-world C++, operators are very much just functions with a different syntax. With this rule, they would have different semantics as well. (What if the operator is called with function syntax? operator+(a, b)?

like image 29
jalf Avatar answered Sep 22 '22 03:09

jalf