Possible way to achieve lazy loading with const objects

Steven Schveighoffer schveiguy at yahoo.com
Fri Sep 30 07:29:22 PDT 2011


On Fri, 30 Sep 2011 09:39:42 -0400, Christophe  
<travert at phare.normalesup.org> wrote:

> "Steven Schveighoffer" , dans le message (digitalmars.D:145812), a écrit  
> :
>> What we are discussing is why opEquals should not be const, not why all
>> functions should not be const.
>
> Considering the viral behavior of const in D, we are discussing why all
> function callable from opEqual should be declared const, even if the
> programmer do not want to use const at all (but obviously want to use
> opEqual.

I think we are past the point where you can use D2 without using const.   
inout should make things better.

Don't forget that not only is const viral, but not-const is viral too.

>> My opinion is:
>>
>> 1. we need const opEquals.  There is no debate on this I think.
>> 2. The compromise solution is not worth the gain.  I'd rather have most  
>> of
>> my objects compare as quickly as possible.
>> 3. It should be possible to create a mutable opEquals and have it hook
>> with obj == obj.  This is different than the compromise solution, which
>> puts both const and non-const opEquals in Object.  This means we need to
>> reengineer how the compiler does opEquals for objects.
>> 4. Yes, it is worth breaking existing compilation to switch to const
>> opEquals in Object.
>
> I think I agree with you, except perhaps on point 4. Can you ellaborate
> point 3 ? I am not sure I understand. Do you talk about hooking obj ==
> obj2 to a mutable opEqual only when obj and obj2 are mutable _and_
> define a mutable opEqual, instead of calling mutable opEqual directly,
> and having it forward to const opEqual at the cost of one extra virtual
> call ?

A while back, opEquals worked like this:

obj1 == obj2 => obj1.opEquals(obj2)

However, since a recent compiler release (in tune with TDPL):

obj1 == obj2 => object.opEquals(obj1, obj2)

where object.opEquals is a function in object.d (not a member function)

Here is the entire function:

     equals_t opEquals(Object lhs, Object rhs)
     {
         if (lhs is rhs)
             return true;
         if (lhs is null || rhs is null)
             return false;
         if (typeid(lhs) == typeid(rhs))
             return lhs.opEquals(rhs);
         return lhs.opEquals(rhs) &&
                rhs.opEquals(lhs);
     }

The changes from the previous version are:

1. if obj1 is null, no segfault
2. if obj1 and obj2 are of different types, both objects' opEquals results  
are taken into account.

However, we lose the ability to define a second opEquals for a  
const/immutable/shared object in opEquals (also, interfaces can no longer  
be compared, but that's a separate bug).

So in order to have an opEquals that works for both const and mutable  
objects, we need to figure out how to make this work.  opEquals inside  
object.di depends on its arguments being Object, so if we go that route,  
Object must define both const and non-const opEquals.  The default  
non-const opEquals in Object will simply call the const one.

But this means a double-virtual call when doing opEquals for const objects.

What I think we need is to make the free function opEquals a template,  
which only instantiates for objects, and then the lhs.opEquals(rhs) and  
rhs.opEquals(lhs) will take full advantage of any overloaded opEquals.

For example, if you wanted to overload for non-const objects.  But I think  
the default in Object should be const.

-Steve


More information about the Digitalmars-d mailing list