www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - InternetAddress comparison fail

reply "Jonathan Marler" <johnnymarler gmail.com> writes:
Why doesn't the equals operator work on the InternetAddress class?

import std.stdio;
import std.socket;
void main()
{
   auto addr1 = new InternetAddress("192.168.0.1", 80);
   auto addr2 = new InternetAddress("192.168.0.1", 80);
   assert(addr1 == addr2); // FAILS
}

If I am not mistaken, the == operator is overriden by the 
opEquals method.  I don't see any opEquals method in std.socket 
so I'm wondering if this is by design or someone overlooked it?
Jan 02 2015
next sibling parent reply "MattCoder" <stop spam.com> writes:
On Saturday, 3 January 2015 at 01:16:39 UTC, Jonathan Marler 
wrote:
 Why doesn't the equals operator work on the InternetAddress 
 class?
It fails as the example below: import std.stdio; class foo{} void main(){ auto a = new foo; auto b = new foo; assert(a == b); } I believe you need to compare the values inside those class right? Anyway, the way I'd do this is changing the line: assert(addr1 == addr2); // FAILS to assert(addr1.toAddrString() == addr2.toAddrString()); Matheus.
Jan 02 2015
next sibling parent "MattCoder" <stop spam.com> writes:
On Saturday, 3 January 2015 at 01:59:40 UTC, MattCoder wrote:
 I believe you need to compare the values inside those class 
 right?
I forgot to paste an example: import std.stdio; class foo{ int i = 0; bool opEquals(foo obj){ return this.i == obj.i;} } void main(){ auto a = new foo; auto b = new foo; assert(a.opEquals(b)); } Matheus.
Jan 02 2015
prev sibling parent reply "Jonathan Marler" <johnnymarler gmail.com> writes:
On Saturday, 3 January 2015 at 01:59:40 UTC, MattCoder wrote:
 On Saturday, 3 January 2015 at 01:16:39 UTC, Jonathan Marler 
 wrote:
 Why doesn't the equals operator work on the InternetAddress 
 class?
It fails as the example below: import std.stdio; class foo{} void main(){ auto a = new foo; auto b = new foo; assert(a == b); } I believe you need to compare the values inside those class right? Anyway, the way I'd do this is changing the line: assert(addr1 == addr2); // FAILS to assert(addr1.toAddrString() == addr2.toAddrString()); Matheus.
Thanks for the suggestion. However, it brings me a little pain to see people use the toAddrString for comparison. An InternetAddress consists of a uint address and a ushort port. The comparison should be 2 integer comparisons. Using toAddrString results in the following steps: 1. Allocate memory for the InternetAddress (GC memory by the way) 2. Convert the uint address to an IP Address string 3. Convert the ushort port to a string. 4. Do steps 1-3 to the second InternetAddress 5. Do a string comparision with the two InternetAddresses. This is so inefficient it hurts me. The steps should be: 1. Compare the uint and ushort members of InternetAddress. done. Anyway, your suggestion works...but I hope you can understand why it hurts me to see it...lol
Jan 03 2015
parent reply "MattCoder" <stop spam.com> writes:
On Saturday, 3 January 2015 at 16:39:05 UTC, Jonathan Marler 
wrote:
 Using toAddrString results in the following steps:
 1. Allocate memory for the InternetAddress (GC memory by the 
 way)
 2. Convert the uint address to an IP Address string
 3. Convert the ushort port to a string.
 4. Do steps 1-3 to the second InternetAddress
 5. Do a string comparision with the two InternetAddresses.
Hmm well, you don't need to convert anything (like ushort to string etc), you can compare the fields between these 2 classes directly: import std.stdio; import std.socket; class myIA : InternetAddress{ this(in char[] addr, ushort port){ super(addr, port); } bool opEquals(myIA obj){ foreach (i, v; this.tupleof) { if(v != obj.tupleof[i]){ return false; } } return true; } } void main(){ auto addr1 = new myIA("192.168.0.1", 80); auto addr2 = new myIA("192.168.0.1", 80); assert(addr1.opEquals(addr2)); } Overall I understood your point/pain, but unfortunately this is what I could do to manage your problem (I'm using D heavily for a couple months now). I'll continue looking over this thread to see what the experts will say. :) Matheus.
Jan 03 2015
parent reply "Jonathan Marler" <johnnymarler gmail.com> writes:
On Saturday, 3 January 2015 at 17:26:29 UTC, MattCoder wrote:
 On Saturday, 3 January 2015 at 16:39:05 UTC, Jonathan Marler 
 wrote:
 Using toAddrString results in the following steps:
 1. Allocate memory for the InternetAddress (GC memory by the 
 way)
 2. Convert the uint address to an IP Address string
 3. Convert the ushort port to a string.
 4. Do steps 1-3 to the second InternetAddress
 5. Do a string comparision with the two InternetAddresses.
Hmm well, you don't need to convert anything (like ushort to string etc), you can compare the fields between these 2 classes directly: import std.stdio; import std.socket; class myIA : InternetAddress{ this(in char[] addr, ushort port){ super(addr, port); } bool opEquals(myIA obj){ foreach (i, v; this.tupleof) { if(v != obj.tupleof[i]){ return false; } } return true; } } void main(){ auto addr1 = new myIA("192.168.0.1", 80); auto addr2 = new myIA("192.168.0.1", 80); assert(addr1.opEquals(addr2)); } Overall I understood your point/pain, but unfortunately this is what I could do to manage your problem (I'm using D heavily for a couple months now). I'll continue looking over this thread to see what the experts will say. :) Matheus.
My problem isn't comparing the two addresses..I can do that using (addr1.addr == addr2.addr && addr1.port == addr2.port) my question was, should the InterenetAddress class have an opEquals or an opCmp or were they ommitted on purpose?
Jan 03 2015
parent "MattCoder" <stop spam.com> writes:
On Saturday, 3 January 2015 at 17:37:19 UTC, Jonathan Marler 
wrote:
 my question was, should the InterenetAddress class have an 
 opEquals or an opCmp or were they ommitted on purpose?
Yes I understood your problem and like I said on the previous post I'm interested on the answer from the experts too. :) Matheus.
Jan 03 2015
prev sibling parent reply "David Eagen" <davideagen mailinator.com> writes:
On Saturday, 3 January 2015 at 01:16:39 UTC, Jonathan Marler 
wrote:
 Why doesn't the equals operator work on the InternetAddress 
 class?

 import std.stdio;
 import std.socket;
 void main()
 {
   auto addr1 = new InternetAddress("192.168.0.1", 80);
   auto addr2 = new InternetAddress("192.168.0.1", 80);
   assert(addr1 == addr2); // FAILS
 }

 If I am not mistaken, the == operator is overriden by the 
 opEquals method.  I don't see any opEquals method in std.socket 
 so I'm wondering if this is by design or someone overlooked it?
I ran into this too and made a helper to do the comparison (using toAddrString) so I could move forward with my project. Adding opEquals and opCmp is probably low-hanging fruit and a good place for someone to start working on Phobos.
Jan 02 2015
parent reply "Jon" <x x.com> writes:
On Saturday, 3 January 2015 at 03:11:05 UTC, David Eagen wrote:
 On Saturday, 3 January 2015 at 01:16:39 UTC, Jonathan Marler 
 wrote:
 Why doesn't the equals operator work on the InternetAddress 
 class?

 import std.stdio;
 import std.socket;
 void main()
 {
  auto addr1 = new InternetAddress("192.168.0.1", 80);
  auto addr2 = new InternetAddress("192.168.0.1", 80);
  assert(addr1 == addr2); // FAILS
 }

 If I am not mistaken, the == operator is overriden by the 
 opEquals method.  I don't see any opEquals method in 
 std.socket so I'm wondering if this is by design or someone 
 overlooked it?
I ran into this too and made a helper to do the comparison (using toAddrString) so I could move forward with my project. Adding opEquals and opCmp is probably low-hanging fruit and a good place for someone to start working on Phobos.
Still, shouldn't the == operator do a deep compare of the two InternetAddress objects in the absence of a defined opEquals method? I don't see why it should fail in the above example. -Jon
Jan 02 2015
parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 1/3/15 12:32 AM, Jon wrote:

 Still, shouldn't the == operator do a deep compare of the two
 InternetAddress objects in the absence of a defined opEquals method? I
 don't see why it should fail in the above example.
InternetAddress is a class. Default comparison for class is identity (refer to the same object). -Steve
Jan 02 2015
parent reply "Jon" <x x.com> writes:
On Saturday, 3 January 2015 at 05:40:33 UTC, Steven Schveighoffer 
wrote:
 On 1/3/15 12:32 AM, Jon wrote:

 Still, shouldn't the == operator do a deep compare of the two
 InternetAddress objects in the absence of a defined opEquals 
 method? I
 don't see why it should fail in the above example.
InternetAddress is a class. Default comparison for class is identity (refer to the same object). -Steve
Thanks for clearing that up - it's been a while since I've played with D. Maybe back in D1 it did a deep compare? The docs still refer to == as doing a comparison of the object's contents though, unless I'm misreading it. Under http://dlang.org/expression: "For class objects, the == and != operators compare the contents of the objects." Maybe this needs to be updated. Thanks, -Jon
Jan 02 2015
parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 1/3/15 12:51 AM, Jon wrote:
 On Saturday, 3 January 2015 at 05:40:33 UTC, Steven Schveighoffer wrote:
 On 1/3/15 12:32 AM, Jon wrote:

 Still, shouldn't the == operator do a deep compare of the two
 InternetAddress objects in the absence of a defined opEquals method? I
 don't see why it should fail in the above example.
InternetAddress is a class. Default comparison for class is identity (refer to the same object). -Steve
Thanks for clearing that up - it's been a while since I've played with D. Maybe back in D1 it did a deep compare? The docs still refer to == as doing a comparison of the object's contents though, unless I'm misreading it. Under http://dlang.org/expression: "For class objects, the == and != operators compare the contents of the objects." Maybe this needs to be updated.
I can see how the wording is confusing, but that statement is somewhat out of context. What it really means is that == and != *should* be comparing the contents. It is an explanatory statement as to why you cannot call obj == null; Because this translates to obj.opEquals(null), if obj is null, then it crashes (well, at least it used to). The true definition of the default is here: https://github.com/schveiguy/druntime/blob/master/src/object_.d#L107 -Steve
Jan 02 2015
next sibling parent reply "Jonathan Marler" <johnnymarler gmail.com> writes:
On Saturday, 3 January 2015 at 06:01:24 UTC, Steven Schveighoffer 
wrote:
 On 1/3/15 12:51 AM, Jon wrote:
 On Saturday, 3 January 2015 at 05:40:33 UTC, Steven 
 Schveighoffer wrote:
 On 1/3/15 12:32 AM, Jon wrote:

 Still, shouldn't the == operator do a deep compare of the two
 InternetAddress objects in the absence of a defined opEquals 
 method? I
 don't see why it should fail in the above example.
InternetAddress is a class. Default comparison for class is identity (refer to the same object). -Steve
Thanks for clearing that up - it's been a while since I've played with D. Maybe back in D1 it did a deep compare? The docs still refer to == as doing a comparison of the object's contents though, unless I'm misreading it. Under http://dlang.org/expression: "For class objects, the == and != operators compare the contents of the objects." Maybe this needs to be updated.
I can see how the wording is confusing, but that statement is somewhat out of context. What it really means is that == and != *should* be comparing the contents. It is an explanatory statement as to why you cannot call obj == null; Because this translates to obj.opEquals(null), if obj is null, then it crashes (well, at least it used to). The true definition of the default is here: https://github.com/schveiguy/druntime/blob/master/src/object_.d#L107 -Steve
So what is the right way to compare the contents of 2 classes? I thought it was to implement an opEquals method. It pains me to see people using the toAddrString function to compare Address classes:( This is so inefficient and unnecessary.
Jan 03 2015
parent reply "Martin Nowak" <code dawg.eu> writes:
On Saturday, 3 January 2015 at 16:33:56 UTC, Jonathan Marler 
wrote:
 So what is the right way to compare the contents of 2 classes?  
 I thought it was to implement an opEquals method.  It pains me 
 to see people using the toAddrString function to compare 
 Address classes:(  This is so inefficient and unnecessary.
Sure, someone should make a pull and implement opEquals for the Address classes, maybe also opHash.
Jan 03 2015
next sibling parent reply Martin Nowak <code+news.digitalmars dawg.eu> writes:
On 01/04/2015 12:45 AM, Martin Nowak wrote:
 Sure, someone should make a pull and implement opEquals for the Address
 classes, maybe also opHash.
In the meantime addr1.tupleof == addr2.tupleof is a useful workaround, but it can't handle polymorphism.
Jan 03 2015
parent "Jonathan Marler" <johnnymarler gmail.com> writes:
On Sunday, 4 January 2015 at 00:13:21 UTC, Martin Nowak wrote:
 On 01/04/2015 12:45 AM, Martin Nowak wrote:
 Sure, someone should make a pull and implement opEquals for 
 the Address
 classes, maybe also opHash.
In the meantime addr1.tupleof == addr2.tupleof is a useful workaround, but it can't handle polymorphism.
Ah I hadn't thought of using tupleof, works nicely. It will compare the entire address struct (sockaddr_in) which is a few extra comparisons then what is needed but that is pretty close. I'll try to think of tupleof more often in the future. Thanks.
Jan 03 2015
prev sibling parent "Jonathan Marler" <johnnymarler gmail.com> writes:
On Saturday, 3 January 2015 at 23:46:01 UTC, Martin Nowak wrote:
 On Saturday, 3 January 2015 at 16:33:56 UTC, Jonathan Marler 
 wrote:
 So what is the right way to compare the contents of 2 classes?
  I thought it was to implement an opEquals method.  It pains 
 me to see people using the toAddrString function to compare 
 Address classes:(  This is so inefficient and unnecessary.
Sure, someone should make a pull and implement opEquals for the Address classes, maybe also opHash.
I've made a pull request (https://github.com/D-Programming-Language/phobos/pull/2839#di cussion_r22435562). I haven't used opEquals that much in D so I'm not super familiar with it. It does concern me a little though. I'm wondering why the type specific opEquals isn't called first before the generic opEquals(Object) method when using the '==' operator. According to the documentation, (a == b), where a and b are classes, is rewritten as ".object.opEquals(a, b)". I'm just wondering why there has to be overhead when using the '==' operator. Instead, the type specific opEquals operator should be called, then if it does not exist, then the generic ".object.opEquals" method should be used. Why isn't it done this way?
Jan 03 2015
prev sibling parent reply "Tobias Pankrath" <tobias pankrath.net> writes:
 I can see how the wording is confusing, but that statement is 
 somewhat out of context. What it really means is that == and != 
 *should* be comparing the contents.

 It is an explanatory statement as to why you cannot call

 obj == null;

 Because this translates to obj.opEquals(null), if obj is null, 
 then it crashes (well, at least it used to).

 The true definition of the default is here:

 https://github.com/schveiguy/druntime/blob/master/src/object_.d#L107

 -Steve
Doesn't TDPL talk about that the correct behaviour is this one https://github.com/schveiguy/druntime/blob/master/src/object_.d#L162 and a == b should be rewritten to opEquals(a, b) which will fallback to identity if a user defined class has no opEquals defined? Could anyone clarify what the actual and intended behaviour is?
Jan 03 2015
parent Martin Nowak <code+news.digitalmars dawg.eu> writes:
On 01/03/2015 05:42 PM, Tobias Pankrath wrote:
 Could anyone clarify what the actual and intended behaviour is?
This [1] is the implementation and it calls opEquals. If that's not overriden, the default [2] will use identity comparison. [1]: https://github.com/D-Programming-Language/druntime/blob/b3a8032e3960480a1588b3d1a4491808b4502d67/src/object_.d#L162 [2]: https://github.com/D-Programming-Language/druntime/blob/b3a8032e3960480a1588b3d1a4491808b4502d67/src/object_.d#L109
Jan 03 2015