www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Qualified class opEquals()

reply Per =?UTF-8?B?Tm9yZGzDtnc=?= <per.nordlow gmail.com> writes:
Is it in the following code possible to make the statement

     assert(car1 == car2);

in the function testEqual() compile in a ` safe pure nothrow 
 nogc context`?

Code:


import core.internal.hash : hashOf;

/** Hash that distinguishes `Expr(X)` from `NounExpr(X)`.
  *
  * See_Also: 
https://forum.dlang.org/post/lxqoknwuujbymolnlyfw forum.dlang.org
  */
hash_t hashOfPolymorphic(Class)(Class aClassInstance)  trusted 
pure nothrow  nogc
if (is(Class == class))
{
     assert(Class.alignof == 8);
     return (cast(hash_t)(cast(void*)typeid(Class)) >> 3) ^ 
hashOf(aClassInstance);
}

version(unittest)
{
     private static:

     class Thing
     {
          property override bool opEquals(const scope Object that) 
const  safe pure nothrow  nogc
         {
             if (typeid(this) !is typeid(that)) { return false; }
             assert(0);
         }
          property final bool opEquals(const scope typeof(this) 
that) const  safe pure nothrow  nogc
         {
             assert(0);
         }
     }

     class Expr : Thing
     {
          safe pure nothrow  nogc:
         alias Data = string;
         this(Data data)
         {
             this.data = data;
         }
          property override bool opEquals(const scope Object that) 
const  safe pure nothrow  nogc
         {
             if (typeid(this) !is typeid(that)) { return false; }
             return data == (cast(typeof(this))(that)).data;
         }
          property final bool opEquals(const scope typeof(this) 
that) const  safe pure nothrow  nogc
         {
             if (typeid(this) !is typeid(that)) { return false; }
             return data == (cast(typeof(this))(that)).data;
         }
          property override hash_t toHash() const  safe pure 
nothrow  nogc
         {
             return hashOf(data);
         }
         Data data;
     }

     class NounExpr : Expr
     {
          safe pure nothrow  nogc:
         this(Data data)
         {
             super(data);
         }
          property override hash_t toHash() const  safe pure 
nothrow  nogc
         {
             return hashOf(data);
         }
     }

     class Year : Thing
     {
          safe pure nothrow  nogc:
         alias Data = long;
          property override hash_t toHash() const  safe pure 
nothrow  nogc
         {
             return hashOf(data);
         }
         Data data;
     }
}

 safe pure nothrow unittest
{
     auto car1 = new Expr("car");
     auto car2 = new Expr("car");
     auto bar1 = new Expr("bar");
     auto ncar = new NounExpr("car");

     void testEqual()  safe pure nothrow  nogc
     {
         assert(car1.opEquals(car2));
         assert(!car1.opEquals(bar1));
         assert(!car2.opEquals(bar1));
         // TODO should compile: assert(car1 == car2);
         assert(hashOf(car1) == hashOf(car2));
         assert(hashOfPolymorphic(car1) == 
hashOfPolymorphic(car2));
     }

     void testDifferent1()  safe pure nothrow  nogc
     {
         assert(!car1.opEquals(bar1));
         // TODO should compile: assert(car1 != bar1);
         assert(hashOf(car1) != hashOf(bar1));
         assert(hashOfPolymorphic(car1) != 
hashOfPolymorphic(bar1));
     }

     void testDifferent2()  safe pure nothrow  nogc
     {
         assert(hashOf(car1) == hashOf(ncar));
         assert(hashOfPolymorphic(car1) != 
hashOfPolymorphic(ncar));
     }

     testEqual();
     testDifferent1();
     testDifferent2();
}
Dec 24 2018
parent reply Paul Backus <snarwin gmail.com> writes:
On Monday, 24 December 2018 at 22:58:03 UTC, Per Nordlöw wrote:
 Is it in the following code possible to make the statement

     assert(car1 == car2);

 in the function testEqual() compile in a ` safe pure nothrow 
  nogc context`?
No, because equality comparison between classes lowers to `object.opEquals` [1], which takes both parameters as `Object`. If you call car1.opEquals(car2) directly, it should work. [1] https://github.com/dlang/druntime/blob/master/src/object.d#L1051
Dec 24 2018
parent reply Per =?UTF-8?B?Tm9yZGzDtnc=?= <per.nordlow gmail.com> writes:
On Tuesday, 25 December 2018 at 00:32:55 UTC, Paul Backus wrote:
 No, because equality comparison between classes lowers to 
 `object.opEquals` [1], which takes both parameters as `Object`.
This is a severe limitation. Are there any plans on fixing this or do I have to wait for Andrei's proposed ProtoObject?
Dec 25 2018
next sibling parent Adam D. Ruppe <destructionator gmail.com> writes:
On Tuesday, 25 December 2018 at 14:27:39 UTC, Per Nordlöw wrote:
 This is a severe limitation. Are there any plans on fixing this 
 or do I have to wait for Andrei's proposed ProtoObject?
Ignore opEquals and use your own interface.
Dec 25 2018
prev sibling parent Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Tuesday, December 25, 2018 7:27:39 AM MST Per Nordlöw via Digitalmars-d-
learn wrote:
 On Tuesday, 25 December 2018 at 00:32:55 UTC, Paul Backus wrote:
 No, because equality comparison between classes lowers to
 `object.opEquals` [1], which takes both parameters as `Object`.
This is a severe limitation. Are there any plans on fixing this or do I have to wait for Andrei's proposed ProtoObject?
ProtoObject _is_ the proposed fix, but if you want to use Object's opEquals in safe code, you can always create a wrapper function that's marked trusted and call that instead. - Jonathan M Davis
Dec 27 2018