There is a debate in a sub-thread about logical const on whether Object.opEquals should be const or mutable.

Right now, it's mutable. This disallows comparison between const objects (except it is technically allowed because the compiler ignores const correctness for this).

I think it should be const.

However, making it const disallows opEquals functions which mutate the object (for lazy loading or caching purposes). I question that this is a major concern, but I have discovered an easy fix that appeases all.

If we make opEquals a template (not Object.opEquals, but the free function opEquals(Object lhs, Object rhs) ), then the template has access to the full type information of the derived object. This means that Object.opEquals can be exclusively const, and you can overload this with a mutable version, and everything just works.

I tried it out by making my copy of druntime use a template (it's actually very few lines change). Although I needed to use casts to compile some parts of phobos (some opEquals calls depend on the compiler ignoring const guarantees as mentioned above), when compiling a simple test program, I can prove it works without compiler changes.

Along with the ability to have both const and non-const (and even technically immutable) opEquals, we have the following drawbacks and benefits:

1. template bloat. Every combination of two object types being compared will generate a new template. 2. inlining of opEquals. Both the free function template, and possibly a final-declared opEquals on a dervied object could be inlined. 3. possible specialization of opEquals(MyDerivedType obj). I don't remember exactly the overloading rules, so this may be impossible. 4. Fixes the issue with interface comparison (see bug http://d.puremagic.com/issues/show_bug.cgi?id=4088), not in the best way, but it would be better than the current situation.

What do people think?

-Steve

Reply via email to