www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - immutable class can't override opEquals, workaround?

reply SimonN <eiderdaus gmail.com> writes:
Hi,

     immutable class A {
         int i;
         this(int arg) { i = arg; }
         override bool opEquals(Object rhsObj)
         {
             auto rhs = cast (immutable(A)) rhsObj;
             return rhs && i == rhs.i;
         }
     }

Error by dmd 2.070:

     ./immutclass.d(4): Error: function immutclass.A.opEquals
     does not override any function, did you mean to override
     'object.Object.opEquals'?

My understandings:

1.  immutable class A means: All methods have immutable tacked
     on them implicitly.
2.  Object.opEquals doesn't have immutable tacked on it. If I
     want to override Object.opEquals, I should override without
     'immutable'.
3.  Overriding opEquals and toHash are necessary to make A
     behave properly as AA key type. This is incompatible with
     (2) in an immutable class.
4.  I found this thread:
         How to turn an inout(Object) into a string
         
http://forum.dlang.org/thread/dcobmtogyrmnaqnqyvbz forum.dlang.org
     that I interpret as: The need for the currently-impossible
     override is acknowledged, but the implementation would bring
     significant changes to the language, therefore the solution
     is postponed. The above thread was from mid-2015, but I guess
     it's still relevant.

My workaround is: Make class _A private, and declare every method
immutable, except for what Object decrees to be mutable/const/...
Then make a public alias A = immutable(_A).

Is there something better than this?

Has there been any new development on Object method removal?
Jonathan M Davis has been pushing this hard 2 years ago, I'd
love to see the efforts make it into the language. :-)

-- Simon
Feb 20 2016
parent reply Jonathan M Davis via Digitalmars-d-learn writes:
On Sunday, February 21, 2016 04:25:59 SimonN via Digitalmars-d-learn wrote:
 Hi,

      immutable class A {
          int i;
          this(int arg) { i = arg; }
          override bool opEquals(Object rhsObj)
          {
              auto rhs = cast (immutable(A)) rhsObj;
              return rhs && i == rhs.i;
          }
      }

 Error by dmd 2.070:

      ./immutclass.d(4): Error: function immutclass.A.opEquals
      does not override any function, did you mean to override
      'object.Object.opEquals'?

 My understandings:

 1.  immutable class A means: All methods have immutable tacked
      on them implicitly.
 2.  Object.opEquals doesn't have immutable tacked on it. If I
      want to override Object.opEquals, I should override without
      'immutable'.
 3.  Overriding opEquals and toHash are necessary to make A
      behave properly as AA key type. This is incompatible with
      (2) in an immutable class.
 4.  I found this thread:
          How to turn an inout(Object) into a string

 http://forum.dlang.org/thread/dcobmtogyrmnaqnqyvbz forum.dlang.org
      that I interpret as: The need for the currently-impossible
      override is acknowledged, but the implementation would bring
      significant changes to the language, therefore the solution
      is postponed. The above thread was from mid-2015, but I guess
      it's still relevant.

 My workaround is: Make class _A private, and declare every method
 immutable, except for what Object decrees to be mutable/const/...
 Then make a public alias A = immutable(_A).

 Is there something better than this?

 Has there been any new development on Object method removal?
 Jonathan M Davis has been pushing this hard 2 years ago, I'd
 love to see the efforts make it into the language. :-)
Okay. Until opEquals, toHash, toString, and opCmp have been removed from Object, you can't override any of them as anything other than mutable. opEquals still works with const and immutable objects via a hack in druntime (it casts away const inside of the free function opEquals which works if your opEquals behaves but results in undefined behavior if it mutates anything). So, I expect that it's simply not possible right now to use a class as a key in an AA, though a struct should work if it's defined appropriately. Certainly, if it's legal to use a class as the key in an AA, it's a bug given that there's no guarantee that it's immutable like a key needs to be. As for actually getting rid of opEquals and friends from Object, no real progress has been made. I finally have a working version of the PR to templatize the free function opEquals such that it will work with opEquals that take a derived class instead of Object (previously, compiler bugs kept getting in the way of it working), but it hasn't even been looked at yet from what I can tell, and it's the simplest of the bits that need to be done (https://github.com/D-Programming-Language/druntime/pull/1439). The overhaul of the AA implementation to templatize it needs to be completed (and I'm not sure where it currently stands) and there will likely have to be some clever compiler changes to make it so that we can remove those 4 functions from Object without breaking code in the process. So, it's going to take a variety of people to get it done, and unfortunately, it hasn't been high on much of anyone's todo list. - Jonathan M Davis
Feb 20 2016
parent SimonN <eiderdaus gmail.com> writes:
On Sunday, 21 February 2016 at 07:58:42 UTC, Jonathan M Davis 
wrote:
 opEquals still works with const and immutable
 if it's legal to use a class as the key in an AA, it's a bug
 have a working version of the PR
 hasn't even been looked at yet from what I can tell,
 and it's the simplest of the bits that need to be done
Thanks for the detailed overview. Judging from the source comment at hack-casting const to mutable, naive improvements affect much more code than I have imagined. The problem and possible solutions are on the radar still, that's satisfying. I understand if it takes more time, even if I too deem it important. -- Simon
Feb 21 2016