www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Required constness of opEquals (and opCmp) ?

reply "monarch_dodra" <monarchdodra gmail.com> writes:
I was wondering: Does Phobos require that user defined opEquals 
(and opCmp) be const?

If someone wants to define a non-const opAssign, I'd say that's 
their problem, but are we (phobos) expected to support it?

The reason I ask is because adding support for this means that 
every type that wraps any other type (which is basically... 
everything), would be required to implement *two* signatures for 
opAssign. Not only that, they'd both have to be conditionally 
implemented...

The context of this question is:
http://forum.dlang.org/thread/urzkfsaqvodhhcnqeoet forum.dlang.org

Basically, a DList of tuples: Problem:
DList has a "const correct" opEquals, but Tuple's isn't. It has:
//----
bool opEquals(R)(R rhs);       //1
bool opEquals(R)(R rhs) const; //2
//----

The problem is that //2 should really be:
//----
bool opEquals(R)(const R rhs) const; //2
//----

However, my question is: Should we even provide //1 at all? Is it 
fine if I deprecate this signature?

My opinion is that supporting non-const opEquals makes no real 
sense, and adds a lot of useless complexity (and inconsistency) 
to the code. At best, it means silently accepting erroneous 
code... Until it explodes in someone else's face...

Opinions?
Jan 02 2013
next sibling parent "Era Scarecrow" <rtcvb32 yahoo.com> writes:
On Wednesday, 2 January 2013 at 09:07:31 UTC, monarch_dodra wrote:
 My opinion is that supporting non-const opEquals makes no real 
 sense, and adds a lot of useless complexity (and inconsistency) 
 to the code. At best, it means silently accepting erroneous 
 code... Until it explodes in someone else's face...

If the code doesn't change anything, it should be const. I know in a sorting algorithmn I am testing with I created a struct that held three numbers. The comparing number, and ordering number (to check against stable sorting) and a counter for how many times that number was compared against. So there could be uses for non-const versions, but those shouldn't affect the rest of the library for a few use cases.
Jan 02 2013
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Wednesday, January 02, 2013 10:07:30 monarch_dodra wrote:
 I was wondering: Does Phobos require that user defined opEquals
 (and opCmp) be const?
 
 If someone wants to define a non-const opAssign, I'd say that's
 their problem, but are we (phobos) expected to support it?
 
 The reason I ask is because adding support for this means that
 every type that wraps any other type (which is basically...
 everything), would be required to implement *two* signatures for
 opAssign. Not only that, they'd both have to be conditionally
 implemented...
 
 The context of this question is:
 http://forum.dlang.org/thread/urzkfsaqvodhhcnqeoet forum.dlang.org
 
 Basically, a DList of tuples: Problem:
 DList has a "const correct" opEquals, but Tuple's isn't. It has:
 //----
 bool opEquals(R)(R rhs);       //1
 bool opEquals(R)(R rhs) const; //2
 //----
 
 The problem is that //2 should really be:
 //----
 bool opEquals(R)(const R rhs) const; //2
 //----
 
 However, my question is: Should we even provide //1 at all? Is it
 fine if I deprecate this signature?
 
 My opinion is that supporting non-const opEquals makes no real
 sense, and adds a lot of useless complexity (and inconsistency)
 to the code. At best, it means silently accepting erroneous
 code... Until it explodes in someone else's face...
 
 Opinions?

This has been discussed quite a bit with regards to classes. We need to be able to support both const and non-const versions of opEquals, opCmp, toHash, and toString. D's const is restrictive enough that it prevents stuff like caching and lazy loading from working properly with const, meaning that we _cannot_ require const. Yes, in most cases, opEquals should be const, but it can't always be, so we can't assume that it is. However, there's a good chance that inout could be used instead if you're worried about duplicating code. - Jonathan M Davis
Jan 02 2013
prev sibling next sibling parent "monarch_dodra" <monarchdodra gmail.com> writes:
On Wednesday, 2 January 2013 at 09:23:55 UTC, Jonathan M Davis 
wrote:
 On Wednesday, January 02, 2013 10:07:30 monarch_dodra wrote:
 I was wondering: Does Phobos require that user defined opEquals
 (and opCmp) be const?
 
 If someone wants to define a non-const opAssign, I'd say that's
 their problem, but are we (phobos) expected to support it?
 
 The reason I ask is because adding support for this means that
 every type that wraps any other type (which is basically...
 everything), would be required to implement *two* signatures 
 for
 opAssign. Not only that, they'd both have to be conditionally
 implemented...
 
 The context of this question is:
 http://forum.dlang.org/thread/urzkfsaqvodhhcnqeoet forum.dlang.org
 
 Basically, a DList of tuples: Problem:
 DList has a "const correct" opEquals, but Tuple's isn't. It 
 has:
 //----
 bool opEquals(R)(R rhs);       //1
 bool opEquals(R)(R rhs) const; //2
 //----
 
 The problem is that //2 should really be:
 //----
 bool opEquals(R)(const R rhs) const; //2
 //----
 
 However, my question is: Should we even provide //1 at all? Is 
 it
 fine if I deprecate this signature?
 
 My opinion is that supporting non-const opEquals makes no real
 sense, and adds a lot of useless complexity (and inconsistency)
 to the code. At best, it means silently accepting erroneous
 code... Until it explodes in someone else's face...
 
 Opinions?

This has been discussed quite a bit with regards to classes. We need to be able to support both const and non-const versions of opEquals, opCmp, toHash, and toString. D's const is restrictive enough that it prevents stuff like caching and lazy loading from working properly with const, meaning that we _cannot_ require const. Yes, in most cases, opEquals should be const, but it can't always be, so we can't assume that it is. However, there's a good chance that inout could be used instead if you're worried about duplicating code. - Jonathan M Davis

Alright, works for me. inout might also get the job done.
Jan 02 2013
prev sibling next sibling parent "monarch_dodra" <monarchdodra gmail.com> writes:
On Wednesday, 2 January 2013 at 09:07:31 UTC, monarch_dodra wrote:
 Basically, a DList of tuples: Problem:
 DList has a "const correct" opEquals, but Tuple's isn't. It has:
 //----
 bool opEquals(R)(R rhs);       //1
 bool opEquals(R)(R rhs) const; //2
 //----

 The problem is that //2 should really be:
 //----
 bool opEquals(R)(const R rhs) const; //2
 //----

Well, at least starting this conversation allowed me to realize that my *fix* to the original problem was wrong...
Jan 02 2013
prev sibling parent =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 01/02/2013 01:07 AM, monarch_dodra wrote:
 I was wondering: Does Phobos require that user defined opEquals (and
 opCmp) be const?

Sorry that I am not adding to this topic directly but I will repeat an observation of mine. My experience is with C++ and D; if there are solutions to this issue in other languages, I am not aware of them. What business does an interface have to affect the implementation of a subclass that it has no idea of? When I introduce a function in an interface (or an abstract base class in C++) I am split between making it const or non-const. const seemingly results in safer user code but either constrains the implementation or forces it to use unsafe casts (or the 'mutable' keyword in C++). non-const is seemingly not restrictive but it lowers the usability of the type. As has already been mentioned, we must embrace 'inout' as a solution and fix issues with its semantics and implementation. Ali
Jan 02 2013