compare two structs via ==

  • Thread starter Thread starter titan nyquist
  • Start date Start date
Jon said:
It's also worth bearing in mind that although the equality operators
aren't generated for you, ValueType.Equals does a memberwise
comparison, using a fast bit comparison where appropriate and calling
Equals on each field otherwise. It's not fast, but it works.

In other words, if you don't care about performance then implementing
== and != can be as simple as calling Equals.

(While I'm on the topic of == and !=, can anyone think of any reason
why you'd ever implement them to return a type other than bool? I
wasn't even aware it could be done until a few days ago.)

Jon

I have create a Data access layer, something like DLinq.
I created a class Expression where operator== yields a new compound
expression:

public static Expression operator==(Expression a, Expression b)
{
return GenerateBinaryExpression("=", a, b);
}

So the syntax allows calls like that:

ProjektstundenTable ps = Tables.Projektstunden;
SelectQuery query = new SelectQuery();
query.From(ps);
query.Select(query.Functions.Sum(ps.fpStunden));

// note that this ==, not beeing a string is NOT evaluated in code
// but instead, it is internally converted to an expression string and
// sent to the database!
query.Where(ps.ProjektRessourcenID==this.ID);
 
Jon said:
(While I'm on the topic of == and !=, can anyone think of any reason
why you'd ever implement them to return a type other than bool? I
wasn't even aware it could be done until a few days ago.)

Fuzzy logic? Return a float value between 0 and 1...
 
I have create a Data access layer, something like DLinq.
I created a class Expression where operator== yields a new compound
expression:

public static Expression operator==(Expression a, Expression b)
{
return GenerateBinaryExpression("=", a, b);
}

Hmm. I can sort of see the benefit, but at the same time it feels
sufficiently unlike the *normal* meaning of == that I'd be loathe to
do something like that myself.

Jon
 
Fuzzy logic? Return a float value between 0 and 1...

I guess my problem with things like that is that it would be such non-
idiomatic C# at that point that I'd rather have a method to explain
what's going on. I guess it just shows that C# wasn't designed
entirely according to my personal preferences :)

Jon
 
Jon said:
I guess my problem with things like that is that it would be such non-
idiomatic C# at that point that I'd rather have a method to explain
what's going on. I guess it just shows that C# wasn't designed
entirely according to my personal preferences :)

Or perhaps it proves that just because you _can_ do something, it might
not be the best idea to do it. :)


Another reason for this that I can think of is the "no" reason. :)

When designing the language, they might simply have found no compelling
reason to limit the == operator to return a bool.
 
Or perhaps it proves that just because you _can_ do something, it might
not be the best idea to do it. :)

Indeed (like relying on the order of initializer execution, to pick an
example from another thread).
Another reason for this that I can think of is the "no" reason. :)

When designing the language, they might simply have found no compelling
reason to limit the == operator to return a bool.

True. Just looking at the language spec, it's at least discouraged:

<quote>
Although it is possible for a user-defined operator to perform any
computation it pleases, implementations that produce results other
than those that are intuitively expected are strongly discouraged. For
example, an implementation of operator== should compare the two
operands for equality and return an appropriate bool result.
</quote>

Jon
 
Usually, but not always.

No - always. That was the definition of equality.

Your other comments indicate that the decision didn't have anything to do
with C# in particular, but language design as a whole. Interesting.

///ark
 
Göran Andersson said:
Ok, but then the definition of equality didn't always make sense.

Do you have an example? Like I said, it seemed to work well for us.

///ark
 
No - always. That was the definition of equality.
As long as the == operator wasn't overloaded, you mean.

We're not talking about overloading ==, since that would imply comparing an
object to a different kind of object. We're talking about comparing an
object to an object of the same class - no overloading.

The behavior of operator== could be overridden, but that I would maintain
that that didn't change the definition of object equality. Someone could
overload == to format your hard drive, but that doesn't change C++'s
definition of equality, which is that two objects are equal iff. all their
members are equal.

But if someone's idea of equality was different from the language's, then
you're right - they could certainly use == to implement that idea. And that
was sometimes done, of course, for legitimate reasons.

It's hard for me to imagine, however, that two objects whose members were
equal to each other would not be equal... But I could be wrong.

And of course "equal" is not the same thing as "identical."

///ark
 
We're not talking about overloading ==, since that would imply comparing
an
object to a different kind of object.

Why would it imply that?

Overloading the == operator is perfectly fine for the purpose of modifying
the default memberwise-compare behavior. For example, when you want two
instances to compare as equal as long as they contain strings that are
identical, even if the strings themselves are different instances.
We're talking about comparing an
object to an object of the same class - no overloading.

I don't see why comparing an object to an object of the same class implies
no overloading.
The behavior of operator== could be overridden, but that I would maintain
that that didn't change the definition of object equality. Someone could
overload == to format your hard drive, but that doesn't change C++'s
definition of equality, which is that two objects are equal iff. all
their
members are equal.

I disagree that that's the only valid definition of equality in C++.
Specifically because of operator overloading.
But if someone's idea of equality was different from the language's, then
you're right - they could certainly use == to implement that idea.And
that
was sometimes done, of course, for legitimate reasons.

It's hard for me to imagine, however, that two objects whose members were
equal to each other would not be equal... But I could be wrong.

In C# that happens all the time. By default if you compare two
references, then even if the members are equal to each other, if the
actual references are not equal the objects are not equal.
And of course "equal" is not the same thing as "identical."

Well, that's my point. "equal" is whatever it has been defined to be ina
particular context. Because of operator overloading, this varies. There
is no one "equals" that is defined.

Pete
 
Mark said:
It's hard for me to imagine, however, that two objects whose members were
equal to each other would not be equal... But I could be wrong.

It's the inequality that is the problem. Just because some of the fields
in two objects are not equal doesn't mean that the obejcts are not
equal. One field in an object may determine if another field should be
included or not when deciding equality.

And also of course if you define two separate instances to be unequal,
as Peter mentioned.
 
Mark said:
Do you have an example? Like I said, it seemed to work well for us.

///ark

Easily:

public struct ValidDouble {
private bool _valid;
private double _value;
...
}

If two values have _valid set to false, you might want to consider them
equal, regardless of the value of _value;
 
Why would it imply that?

Overloading means adding another method with the same name but a different
signature. It's easy to confuse overloading with overriding, as my own post
proved. :)

The non-overloaded operator== that C++ automatically generates takes as its
argument a member of the same class or a base class of the same class
(IIRC). Overloading means to leave that method alone and add another method
that takes, for example, an int as the argument. I believe you're talking
about overriding, where a child class overrides a parent class method (with
the same signature) to do something different than the parent.
Overloading the == operator is perfectly fine for the purpose of modifying
the default memberwise-compare behavior. For example, when you want two
instances to compare as equal as long as they contain strings that are
identical, even if the strings themselves are different instances.

Actually, that would be encompassed by a plain ol' memberwise compare.
Strings with identical contents are indeed equal. To just compare the
addresses would be the old bitwise comparison.
In C# that happens all the time. By default if you compare two
references, then even if the members are equal to each other, if the
actual references are not equal the objects are not equal.

I think that would be confusing, since equality is different from
identicality (?).
Well, that's my point. "equal" is whatever it has been defined to be in a
particular context. Because of operator overloading, this varies. There
is no one "equals" that is defined.

"Equals" has indeed been defined in C++ as I explained. This is proven by
the fact that it used to be different in earlier versions of the language.
You're right that one can change the behavior of an operator with two sets
of two lines to mean anything one wants (including global thermonuclear
war). But I maintain that the language itself is clear on the concept.

But this is a semantic difference. I think we each know what the other is
talking about (pace the overloading/overriding business).

///ark
 
Göran Andersson said:
public struct ValidDouble {
private bool _valid;
private double _value;
...
}

If two values have _valid set to false, you might want to consider them
equal, regardless of the value of _value;

Good example. I stand corrected.

So I'll restate :). Memberwise comparison makes sense in the vast majority
of structures and classes that I've defined or seen defined.

///ark
 
Overloading means adding another method with the same name but a
different
signature. It's easy to confuse overloading with overriding, as my own
post
proved. :)

I get your gist, but for better or worse (you may argue "worse" :) ),
redefining the behavior of an operator in C++ (and I think C# too) is
always called "overloading". That's why, for example, there are document
pages for "Operator Overloading" but none for "Operator Overriding".
The non-overloaded operator== that C++ automatically generates takes as
its
argument a member of the same class or a base class of the same class
(IIRC). Overloading means to leave that method alone and add another
method
that takes, for example, an int as the argument. I believe you're talking
about overriding, where a child class overrides a parent class method
(with
the same signature) to do something different than the parent.

How is the syntax for what you call an "operator override" different from
the syntax described in the documentation for "Operator Overloading"
(http://msdn2.microsoft.com/en-us/library/5tk49fh2.aspx, for example)?
And why does the C# documentation use the terms "override" and "overload"
interchangeably in this page:
http://msdn2.microsoft.com/en-us/library/ms173147.aspx

Again, I understand where you're coming from, but the real world does not
use such black & white distinctions between "overload" and "override", and
so if that's the only complaint you've got about my comment about
overloading the == operator, I think you're making too much hay overit.
Actually, that would be encompassed by a plain ol' memberwise compare.
Strings with identical contents are indeed equal. To just compare the
addresses would be the old bitwise comparison.

Actually, it would not. I'm talking about a class that contains
*references* to strings, and a member-wise compare will not detect the
equality case when the strings contain identical data but are different
references.
I think that would be confusing, since equality is different from
identicality (?).

I'm not sure what you mean here. You wrote "It's hard for me to imagine,
however, that two objects whose members were
equal to each other would not be equal... But I could be wrong." I
replied by pointing out that with the default reference-equality behavior,
even when members are the same, the objects are not equal.

Whether you think it would be confusing isn't relevant as far as I can
tell. The fact is, that's how it works. I gave an example of a situation
in which two objects are considered not equal even though they have
members that are equal.
"Equals" has indeed been defined in C++ as I explained.

And as I explained, what's "equal" depends on how you've defined the ==
operator. It's not an absolute.

Pete
 
And why does the C# documentation use the terms "override" and "overload"
interchangeably in this page:
http://msdn2.microsoft.com/en-us/library/ms173147.aspx

It doesn't - you *override* the single method signature

bool Equals(object other)

but you *overload* the == operator by providing different signatures,
eg
bool operator ==(string x, string y)
bool operator ==(DateTime x, DateTime y)

Is there anything in the article which goes against that? I could see
anything in a brief skim, but I'm happy to look at any particular bits
more closely.
Again, I understand where you're coming from, but the real world does not
use such black & white distinctions between "overload" and "override", and
so if that's the only complaint you've got about my comment about
overloading the == operator, I think you're making too much hay over it.

I haven't been following the conversation closely enough, but overload
and override are pretty well defined in the C# and .NET world.
 
but you *overload* the == operator by providing different signatures,
eg
bool operator ==(string x, string y)
bool operator ==(DateTime x, DateTime y)

You seem to be in agreement with me. Mark's claim was that it's only
"overloading" when the types are different. However, both of your
examples show using the == operator on identical types. This is theway
I'm using the phrase "overload" as well.
Is there anything in the article which goes against that? I could see
anything in a brief skim, but I'm happy to look at any particular bits
more closely.

Look at the text in the section named "Overriding Operator ==":

By default, the operator == tests for reference equality by determining
if two references indicate the same object, so reference types do not
need to implement operator == in order to gain this functionality. When
a type is immutable, meaning the data contained in the instance cannot
be
changed, overloading operator == to compare value equality instead of
reference equality can be useful because, as immutable objects, they
can
be considered the same as long as they have the same value. Overriding
operator == in non-immutable types is not recommended.

Overloaded operator == implementations should not throw exceptions. Any
type that overloads operator == should also overload operator !=. For
example:

I do not read that text as talking about anything other than changing the
behavior of the == operator in a specific case. But within two
paragraphs, the word "override" is used only once (twice, if you count the
heading), while the word "overload" is used four times. As near as I can
tell, the words are used interchangeably.
I haven't been following the conversation closely enough, but overload
and override are pretty well defined in the C# and .NET world.

I certainly understand the distinction (even if I've confused the two on
occasion in the past :) ). However, I have only ever called the act of
changing an operator's beahvior "overloading", even when I haven't changed
the types involved in the comparison. Nor have I ever seen documentation
that makes a clear distinction between the two in that case. Even in the
context of C#, where the two terms are clearly distinct as applied to
methods, when talking about operators, the same care is not taken to
distinguish the two.

Pete
 
Peter Duniho said:
You seem to be in agreement with me. Mark's claim was that it's only
"overloading" when the types are different. However, both of your
examples show using the == operator on identical types. This is the way
I'm using the phrase "overload" as well.

It's not that the types are different to each other within the
signature - it's that the *signatures* are different.

Basically, if the string type didn't overload the == operator with

bool operator ==(string x, string y)

then there wouldn't be any such operator. There's be the implicit

bool operator ==(object x, object y)

but that's got a different signature, so isn't overridden by the string
one. (And wouldn't be anyway, as they're always static... which I
realise I haven't included above.)
Look at the text in the section named "Overriding Operator ==":

By default, the operator == tests for reference equality by determining
if two references indicate the same object, so reference types do not
need to implement operator == in order to gain this functionality. When
a type is immutable, meaning the data contained in the instance cannot
be
changed, overloading operator == to compare value equality instead of
reference equality can be useful because, as immutable objects, they
can
be considered the same as long as they have the same value. Overriding
operator == in non-immutable types is not recommended.

Overloaded operator == implementations should not throw exceptions. Any
type that overloads operator == should also overload operator !=. For
example:

I do not read that text as talking about anything other than changing the
behavior of the == operator in a specific case. But within two
paragraphs, the word "override" is used only once (twice, if you count the
heading), while the word "overload" is used four times. As near as I can
tell, the words are used interchangeably.

"Overriding" there is a mistake. As operators are implemented as static
methods, they can't be overridden. Apologies for not finding it before
- I looked for "override" which of course misses "overriding".
I certainly understand the distinction (even if I've confused the two on
occasion in the past :) ). However, I have only ever called the act of
changing an operator's beahvior "overloading", even when I haven't changed
the types involved in the comparison. Nor have I ever seen documentation
that makes a clear distinction between the two in that case.

There's no such thing as operator overriding, basically - could you
given an example where you think you *have* been doing what you'd call
operator overriding?
Even in the
context of C#, where the two terms are clearly distinct as applied to
methods, when talking about operators, the same care is not taken to
distinguish the two.

It is by some - just not by all :)
 
Back
Top