On Fri, 30 Sep 2011 09:39:42 -0400, Christophe
<trav...@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