www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Should this be correct behaviour?

reply "Janice Caron" <caron800 googlemail.com> writes:
Should this be correct behaviour?

    float[] f = new float[1];
    float[] g = f.dup;
    assert(f == g); /* Passes */
    assert(f[0] == g[0]); /* Fails */

Certainly it is correct for the second assert to fail, because f[0]
and g[0] both contain nan, and as we all know, (nan != nan).
Essentially, the second assert (correctly) fails because the elements
have not been initialised, and so we can't do the compare.

My question is, shouldn't the first assert also fail?

Put another way, how can two arrays be considered equal, if their
elements are not considered equal?

I realise that everything is behaving according to spec. But is it sensible?
Nov 29 2007
parent reply Walter Bright <newshound1 digitalmars.com> writes:
Janice Caron wrote:
 Should this be correct behaviour?
Yes.
     float[] f = new float[1];
     float[] g = f.dup;
     assert(f == g); /* Passes */
     assert(f[0] == g[0]); /* Fails */
 
 Certainly it is correct for the second assert to fail, because f[0]
 and g[0] both contain nan, and as we all know, (nan != nan).
 Essentially, the second assert (correctly) fails because the elements
 have not been initialised, and so we can't do the compare.
 
 My question is, shouldn't the first assert also fail?
 
 Put another way, how can two arrays be considered equal, if their
 elements are not considered equal?
You are comparing two array *references* which point to the same array. The two references clearly are the same. (f == g) does not compare the contents of the arrays.
 I realise that everything is behaving according to spec. But is it sensible?
Yes: float a; float b = a; assert(b == a); // fails And this is how floating point works.
Nov 29 2007
next sibling parent reply BCS <ao pathlink.com> writes:
Reply to Walter,

 Janice Caron wrote:
 
 float[] f = new float[1];
 float[] g = f.dup;
 assert(f == g); /* Passes */
 
 My question is, shouldn't the first assert also fail?
  
You are comparing two array *references* which point to the same array.
That dup should have copied. The references should not be equal.
Nov 29 2007
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
"BCS" wrote
 Reply to Walter,

 Janice Caron wrote:

 float[] f = new float[1];
 float[] g = f.dup;
 assert(f == g); /* Passes */

 My question is, shouldn't the first assert also fail?
You are comparing two array *references* which point to the same array.
That dup should have copied. The references should not be equal.
my guess is the function to compare arrays of any type does a bit for bit compare? from what I can see in the docs, comparing two arrays is only defined for strings. -Steve
Nov 29 2007
parent reply Sean Kelly <sean f4.ca> writes:
Steven Schveighoffer wrote:
 "BCS" wrote
 Reply to Walter,

 Janice Caron wrote:

 float[] f = new float[1];
 float[] g = f.dup;
 assert(f == g); /* Passes */

 My question is, shouldn't the first assert also fail?
You are comparing two array *references* which point to the same array.
That dup should have copied. The references should not be equal.
my guess is the function to compare arrays of any type does a bit for bit compare?
Nope. It calls _adEq, which in turn calls TypeInfo_Af.equals, which then calls TypeInfo_f.equals for each element. The problem is that TypeInfo_f.equals is implemented to return true if either a and b are equal *or* if a and b are both NaN. I have no idea why it does this. Sean
Nov 29 2007
parent reply Derek Parnell <derek nomail.afraid.org> writes:
On Thu, 29 Nov 2007 13:29:00 -0800, Sean Kelly wrote:

 Steven Schveighoffer wrote:
 my guess is the function to compare arrays of any type does a bit for bit 
 compare?
Nope. It calls _adEq, which in turn calls TypeInfo_Af.equals, which then calls TypeInfo_f.equals for each element. The problem is that TypeInfo_f.equals is implemented to return true if either a and b are equal *or* if a and b are both NaN. I have no idea why it does this.
I don't know which is better either as I can see arguments for both. (1) If (a[n] != b[n]) is true then (a == b) should be false. however ... (2) If .dup is designed to make an exact copy of an array then the resulting array should be equal to the original array. I'm tending to think that I prefer the existing D behaviour because it allows easier generic code for templates and just 'feels' right. -- Derek (skype: derek.j.parnell) Melbourne, Australia 30/11/2007 10:25:36 AM
Nov 29 2007
next sibling parent reply Sean Kelly <sean f4.ca> writes:
Derek Parnell wrote:
 On Thu, 29 Nov 2007 13:29:00 -0800, Sean Kelly wrote:
 
 Steven Schveighoffer wrote:
 my guess is the function to compare arrays of any type does a bit for bit 
 compare?
Nope. It calls _adEq, which in turn calls TypeInfo_Af.equals, which then calls TypeInfo_f.equals for each element. The problem is that TypeInfo_f.equals is implemented to return true if either a and b are equal *or* if a and b are both NaN. I have no idea why it does this.
I don't know which is better either as I can see arguments for both. (1) If (a[n] != b[n]) is true then (a == b) should be false. however ... (2) If .dup is designed to make an exact copy of an array then the resulting array should be equal to the original array. I'm tending to think that I prefer the existing D behaviour because it allows easier generic code for templates and just 'feels' right.
For what it's worth, I think the reason for the current behavior is to allow sane interaction with AAs. If NaNs compared not equal via TypeInfo comparisons then any NaN used as an AA key would result in an insertion that was lost forever. With this in mind, I think the current behavior makes the most sense as well. Sean
Nov 29 2007
parent reply "Janice Caron" <caron800 googlemail.com> writes:
On Nov 30, 2007 12:23 AM, Sean Kelly <sean f4.ca> wrote:
 If NaNs compared not equal via
 TypeInfo comparisons
They don't compare not equal even in normal use. They compare as being neither == nor !=. (I know you know that. Just trying to be precise here).
 then any NaN used as an AA key would result in an
 insertion that was lost forever.  With this in mind, I think the current
 behavior makes the most sense as well.
There is another way of looking at it though. Using NaN as array key sounds like a bug to me. Should it even be permitted? Let's think this through - the interpretation of NaN here is either "unassigned variable", or "I don't know the answer" (for example, infinity divided by infinity). Is it even sensible to allow such a beast to be an array key?
Nov 29 2007
parent Sean Kelly <sean f4.ca> writes:
Janice Caron wrote:
 On Nov 30, 2007 12:23 AM, Sean Kelly <sean f4.ca> wrote:
 If NaNs compared not equal via
 TypeInfo comparisons
They don't compare not equal even in normal use. They compare as being neither == nor !=. (I know you know that. Just trying to be precise here).
 then any NaN used as an AA key would result in an
 insertion that was lost forever.  With this in mind, I think the current
 behavior makes the most sense as well.
There is another way of looking at it though. Using NaN as array key sounds like a bug to me. Should it even be permitted? Let's think this through - the interpretation of NaN here is either "unassigned variable", or "I don't know the answer" (for example, infinity divided by infinity). Is it even sensible to allow such a beast to be an array key?
Probably not. I guess the array code could test if the value being inserted were equal to itself and if so, throw an exception? Seems a bit of a corner case to test for explicitly though. Sean
Nov 30 2007
prev sibling parent "Janice Caron" <caron800 googlemail.com> writes:
On Nov 29, 2007 11:32 PM, Derek Parnell <derek nomail.afraid.org> wrote:
 (1) If (a[n] != b[n]) is true then (a == b) should be false.
I didn't say that (a[n] != b[n]) is true. I said that (a[n] == b[n]) is false. Not the same. In fact, (a[n] == b[n]) and (a[n] != b[n]) are both false. So we might suppose that (a == b) and (a != b) should also both be false.
 I'm tending to think that I prefer the existing D behaviour because it
 allows easier generic code for templates and just 'feels' right.
I don't actually have an opinion one way or the other. Both approaches feel equally right to me. I just wanted to make sure we all understood the behaviour, and that there was some consensus on which approach is most sensible. Sean's analysis is interesting though. His comment "I have no idea why it does this." is one that I'd like to see answered.
Nov 29 2007
prev sibling parent reply "Janice Caron" <caron800 googlemail.com> writes:
On 11/29/07, Walter Bright <newshound1 digitalmars.com> wrote:
     float[] f = new float[1];
     float[] g = f.dup;
     assert(f == g); /* Passes */
     assert(f[0] == g[0]); /* Fails */

 My question is, shouldn't the first assert also fail?

 Put another way, how can two arrays be considered equal, if their
 elements are not considered equal?
You are comparing two array *references* which point to the same array. The two references clearly are the same.
I don't see why. I duped the array.
 (f == g) does not compare the contents of the arrays.
I don't understand that. It must do. Isn't that how == works for arrays?
 I realise that everything is behaving according to spec. But is it sensible?
Yes: float a; float b = a; assert(b == a); // fails And this is how floating point works.
I meant, is it sensible that (f == g), given that (f[0] == g[0]) is false?
Nov 29 2007
parent Don Clugston <dac nospam.com.au> writes:
Janice Caron wrote:
 On 11/29/07, Walter Bright <newshound1 digitalmars.com> wrote:
     float[] f = new float[1];
     float[] g = f.dup;
     assert(f == g); /* Passes */
     assert(f[0] == g[0]); /* Fails */

 My question is, shouldn't the first assert also fail?

 Put another way, how can two arrays be considered equal, if their
 elements are not considered equal?
You are comparing two array *references* which point to the same array. The two references clearly are the same.
I don't see why. I duped the array.
 (f == g) does not compare the contents of the arrays.
I don't understand that. It must do. Isn't that how == works for arrays?
 I realise that everything is behaving according to spec. But is it sensible?
Yes: float a; float b = a; assert(b == a); // fails And this is how floating point works.
I meant, is it sensible that (f == g), given that (f[0] == g[0]) is false?
Whenever that situation happens, we also have (f == f) even when (f[0] == f[0]) is false. It's really quite unfortunate that the normal floating point == is defined to be false for NaNs, rather than being a simple bitwise comparison. It wrecks generic code, and it eliminates huge classes of optimisation opportunities. IMHO, a different operator should have been invented; but that's the fault of IEEE754, not D. At least we can control the damage by restricting the unhelpful behaviour to the built-in FP types. A function call could be provided for the case when you really want it to fail if there are any NaNs in either of the arrays. But "containsNaN(arr[])" is probably more useful in that situation anyway.
Nov 30 2007