How will we fix opEquals?

Steven Schveighoffer schveiguy at yahoo.com
Thu Feb 10 10:59:24 PST 2011


On Thu, 10 Feb 2011 12:24:02 -0500, Jason House  
<jason.james.house at gmail.com> wrote:

> Steven Schveighoffer Wrote:
>
>> On Thu, 10 Feb 2011 09:15:36 -0500, Jason House
>> <jason.james.house at gmail.com> wrote:
>>
>> > Don Wrote:
>> >
>> >> Andrei once stated a worthy goal: as far as possible, const should be
>> >> opt-in: it should be possible to code without requiring const on
>> >> everything.
>> >>
>> >> opEquals() is in conflict with this, since it is a member function of
>> >> Object.
>> >>
>> >> (1) If it is a const member function, then it will have a viral  
>> effect
>> >> on all objects -- any function called by opEquals will have to be  
>> marked
>> >> const.
>> >> (2) If it is not const, then const objects cannot be compared!
>> >>
>> >> Currently, it's not const,  but the problem isn't visible because of
>> >> compiler bug 5080. (Same problem applies to opCmp).
>> >>
>> >> How will we break this dilemma?
>> >
>> > class LazyObject{
>> >   bool OpEquals(LazyObject);
>> > }
>> >
>> > class Object : LazyObject{
>> >   override bool OpEquals(LazyObject) const;
>> >   bool opEquals(const Object) const;
>> > }
>> >
>> > By default, all classes derive from Object, but those that want to
>> > ignore viral const or implement lazy calculations can derive from
>> > LazyObject.
>>
>> This doesn't work.  What if the user overrides one and not the other?   
>> Or
>> the semantics are different?  Then const objects compare differently  
>> than
>> non-const ones.
>>
>> -Steve
>
> You can never stop programmers from writing incorrect code...

No but you can make things easier to avoid writing incorrect code.  This  
kind of change invites mistakes, because it looks like you have to  
completely duplicate your logic, and forgetting to modify one and not the  
other happens to even seasoned veterans.

>
> The way I envision this, "bool opEquals(LazyObject) const" would rarely  
> be overridden. I would recommend writing it in terms of the other  
> function. Something akin to the following:
> bool OpEquals(LazyObject o) const{
>   auto x = cast(const Object) o;
>   if (x is null)
>     return false;
>   return (this==x);
> }

This also doesn't work without extra effort -- overriding less than the  
full overload set results in runtime hidden function errors.  You need to  
alias the base class' method, in *every* derived class.

I don't really think adding extra complexity makes things better.  I think  
a single overload for opEquals (which is const) is fine.  Anything beyond  
that can use a separate method name, and you just call the method directly.

-Steve


More information about the Digitalmars-d mailing list