Operator overloading

mskeel

Senior Contributor
Joined
Oct 30, 2003
Messages
913
This is a continuation of a thread that accidentally got carried away. Sorry about that.

Nerseus said:
Let me sum it up: if you like operator overloading, use it. If you don't, don't. If you overload Equals on a reference type (class), I don't care - just don't come work for me
I agree but I am confused by your ending remark. You seem to be implying that overloading the equals operator on a class is bad. Maybe I am confused by my C++ background but, if you dereference the pointers and check the values for equality what's the big deal? Is there something I'm missing here? Obviously if you do a shallow check then you can get very wrong results, but a deep check should work just fine. I mean, overlaoding == in a class is the whole point so why would it be bad?
 
In my opinion, an == check on a reference type should always mean the same thing - am I pointing at the exact same object. If I want to see if two separate instances of a Customer class represent the same customer (say, defined by a CustomerNumber field) then I'd compare on CustomerNumber or add a more suitable method.

For Value types, if I'm going to compare them, I would definitely override == and Equals for performance reasons.

-ner
 
+, -, ++, --, <, >, <<, >>, * and / are not defined either for structs or classes. There is no ambiguity in operator overloading here. == and != are not defined for structs. There is no ambiguity here. For classes (and Nerseus shares my sentiments here), == and != are already defined. When you overload the == operator for a class, you aren't adding behavior, you are modifying it, hence you introduce ambiguity.

For example, a programmer writes a custom ListViewItem class and overloads the == and != operators. If he unwittingly uses the == operator to check for equal reference, he encounters logic errors. On the other hand, if he pulls them directly from a ListViewItemCollection and uses the == operator to see if two are equivalent, he will inadvertently be checking for equal references, and again encounter a logic error.

+ always adds things. * always multiplies. == compares references on reference types. If you overload an operator and define it to do something other than what is expected you are bound to confuse people and cause problems. (We could make an exception for << and >>, since they are probably better know as stream operators than bitshift operators in C++.) From where I stand, overloading == to compare a few fields of two objects is akin to doing something like overloading + to change the Name property of your control in that you are not simply implementing the operator for a class, you are changing what that operator does.

mskeel said:
Maybe I am confused by my C++ background but, if you dereference the pointers and check the values for equality what's the big deal?
The C++ analogy isn't really applicable. Casting to an Object is not the same a dereferencing, and neither is using the Object.Equals() function. You don't get to see the pointers in .Net. In C++ the reference and the object it refers to are two entirely separate entities and can be handled separately, so there is no conflict when it comes to operator overloading. == is not predefined for classes, and you can not redefine it for pointers. In C# or VB, the reference and the object are unified to an extent (notice that we don't have the -> operator in C#), and their behavior is somewhere between that of a C++ pointer and a C++ class. We don't have the luxury of treating the object and the pointer as separate entities. There is no such thing as dereferencing a .Net reference.

So when you overload the C# == operator, in C++ terms it is more like overloading the == operator for a pointer to your class than overloading the operator on the class itself. Think about comparing two pointers to ExampleClass objects and experiencing bizarre behavior because the creator of the class found a way to overload the == operator for the type *ExampleClass instead of ExampleClass.
 
nerseus said:
For Value types, if I'm going to compare them, I would definitely override == and Equals for performance reasons.
The performance argument isn't going to wash for me. Overloading operators ins't about performance, it's about readability. When I see an equals operator between two variables, I assume that you are actually checking for equality -- not whether two variables point to the same place in memory. You should use Object.ReferenceEquals() (as marble earlier pointed out) to do that. The fact that Object.Equals is the same as ReferenceEquals for Objects is merely a coincidence in the case of Objects and should not dictate behaviour for all things that inherit from type Object.

Look at the String class. The string class inherits from Object and overloads the equals operator. That equals operator, by definition, "Determines whether two String objects have the same value." Not whether two string have the same reference which is the result you would get by casting string to an object and then checking equality or using the Object.ReferenceEquals method. Choose just about any Class where an equals operator makes sense and you'll find that it has been overloaded. It makes no sense to not do the same in classes you write.

That fact that you couldn't overload operators in VB.Net 1.1 doesn't mean that you shouldn't now that you can in VB.Net 2.0. Not being able to overload operators in VB.Net 1.1 was a deficiency, not a feature.

I'm not trying to start any fights here, so please don't take this as being hostile. It just seems like you guys think that overloading equals is bad and since you seem like smart people I want to understand why you think that way becuase I don't see it.
 
I can't explain my point of view any more clearly. Ambiguity and potential for logic errors. Here's another: breaking changes. You upgrade your component from .Net 1.1 to 2.0. You think that it would be nifty to use == to compare for equivalency, overload ==, and all of a sudden nothing works. Why? All your old code used == to check references. == has always meant the same thing for everything except elemental (or instrinsic if you prefer) types: reference comparison.

Operator overloading, with the exception of ==, only adds functionality. Overloading == does not simply add function, it modifies it. The objection to overloading == is all the implications of modifying something as elementary as the definition of equality. In .Net, equality is defined (until redefined) as binary equality for simple types, reference equality for reference type, and not defined for value types, so don't break out your dictionary.

I understand your point of view, I just disagree. I don't expect you to agree with me, but I have put it half a dozen ways and if you still don't at least understand then I don't know what to tell you.

Also...
mskeel said:
The string class inherits from Object and overloads the equals operator.
The fact that the equals operator behaves irregularly on Strings isn't a matter of operator overloading. No where in the .Net Framework is the == operator redefined for Strings. VB and C# compilers translate a == between two strings into a String.Equals() call. The compilers give Strings special treatment so that they appear to behave like a value type. That is a language feature, and not an operator overload. Operator overloading is language independant.

mskeel said:
When I see an equals operator between two variables, I assume that you are actually checking for equality -- not whether two variables point to the same place in memory.
Are you not a veteran of .Net 1.0/1.1?
 
I understand completely everything that you are saying. I think that your perspective is interesting, but I do not share your opinions. The whole point here is that you are overloading the equals operator, not rewriting. It's not like == suddenly goes away for your object as an Object just becuase you wrote an equals method that (in languages such as C++) is completely sane and normal becuase it determines the actual equality of two objects -- the data in those objects which is what makes them equal.

By the way, the C++ analogy fits just fine. You can always use the address of operator (&) to get the address of a pointer and do a check to determine if the memory locations are the same.

I guess I just don't use == the same way you guys do. I don't have any of the problems of concerns that you have expressed. From everything you've said so far, I don't see anything wrong with using == to actually check for equality in classes. I was afraid that there was some usage standard that I didn't know about or some crazy thing that makes it not good to do, but so far all I've seen are opinions that I just don't agree with. Not a big deal. Thanks for the debate.
 
Maybe I am confused by my C++ background but, if you dereference the pointers and check the values for equality what's the big deal?
How does this apply to C#?

Let me explain, again, why this analogy is not valid. I know you can use the address of operator and compare addresses, in C++. My whole point is that there is no equivalent to this in C#; no address of operator, and no pointers, hence your analogy is not whole. In other words, using the general "A is to B as C is to D" representation of an analogy, Pointer comparison is to C++ as what is to C#? Object.Equals and Object.ReferenceEquals are not the same.

The closest thing is the C# default == operator, which compares pointers, inline, with no function call. If anything, your C++ background should compel you to leave == alone so that you could have an operator to compare pointers without unnecessary casting or function calls.


And, hey, to each his own. If you like to overload ==, fantastic. By all means, do. It is simply frustrating when you seem blind to the merits of leaving it as it is, and to the difference between adding function and modifying function.
 
Kruger and Epley dug deeper to uncover the reasons behind e-mailers' overconfidence. They suspected that it might be because e-mailers assume that other people have the same inside information about their intentions and motivations that they do–what social psychologists call egocentrism.
Obviously, I'm going to assume that the link is some sort of statement you consider to be relevant to this thread, and on that note, I acknowledge that it is an interesting point.

I'm going to be blunt, at the risk of sounding like a pompous *****. Every "discovery" uncovered through a study and every insight as to a why or how from that article strikes me as common sense. Anyone who spends any amount of time on the Internet quickly realizes the potential for miscommunication, and anyone who spends any amount of time in reality should realize that not everyone knows what he knows. I don't need a study to tell me that.

I keep these things in mind when I post anything on the Internet. I always have, especially when something is subjective, because not everyone shares my morals and most elemental of principals, whether the topic is programming practice or abortion. I explain my self as explicitly as possible, avoiding any sort of ambiguity and any means of misinterpretation. You can tell me I'm offensive. You can tell me that I'm wrong. I won't take it too personally, but when you tell me that I'm not clear in my meaning, I'm confounded.

I explain in plain English, and then elaborate in precise logic. I note what I base on preference, practice, or principal. Then I reiterate, demonstrate, and summate (mmm... rhymes). Maybe not everyone is as systematic and logically direct in his manner of thinking and communicating as I am. Maybe I try to spin a web of logic and tie people up. I don't know. I seem to be misunderstood more often than I like to admit, considering how hard I try to be perfectly clear. Maybe it’s just me. I'll try again. Tell me how I do.



I don't like to overload ==. It can be confusing because what used to compare references can do different things now. I make a practice of not overloading == for the sake of avoiding this confusion. It guaruntees that I can compare reference equality of my objects with ==, because to me this is what makes sense. Is this more clear? Or maybe I could have given an example to demonstrate.

Given the class SimpleClass:
C#:
public class SimpleClass
    public int i;
 
    public SimpleClass(int value){
        i = value;
    }

    public operator == (SimpleClass A, SimpleClass B){
        return A.i == B.i;
    }
End Class
We declare the following variables and objects:
C#:
SimpleClass A = new SimpleClass(5);
SimpleClass B = A;
SimpleClass C = new SimpleClass(5);
Our current situation can be represented as figure (I). We could say that A == B, B == C, and C == A. All three variables are the same. Now, we modify memory using the code below. We are working in a different class in a different file on a different day. It could even be a different person writing this code. We don't have the original declaration of A, B, and C in front of us, so we don't have a clear definition of what the variables mean in relation to eachother.
C#:
A.i = 7;
Now our situation can be such as represented in figure (II).

We only changed A, not B or C, but now B is equal to A and C is not, and additionally, B and C no longer maintain their equality. How can changing A affect the relevance between B and C. Looking at the before and after pictures of equality, you would think that you changed the value of C instead of A. If SimpleClass were a struct this wouldn't have happened, and if SimpleClass didn't overload == this wouldn't have happened.

Is equality defined as being the same entity, or unique but equivalent entities? It is no longer only one or the other, but instead any of the above. You can compare and see that A == B == C, but you can't depend on that to mean either that changing A will change B and C as well or that changing A will have no effect on B or C.

For this one specific reason, I think that overloading == is bad. That's just my take. Now I have shown you a specific example, though, and I don't see any way for someone to not understand my point.
 

Attachments

I didn't really want to revisit this because I felt this thread had taken a turn for the worse (like an awkward lovers' quarrel everybody cleared the room for), but then I thought about the Is operator which is used to determine if two object references refer to the same object and thought it might be worth continuing this discussion. Why would you use the equals operator when you could use the Is operator for Visual Basic?

The bottom line with regards to overloading the equals operator seems to come down to personal preference, but I just thought that it was interesting that there are three ways to determine if two objects reference the same memory: Object's equals operator, Object.ReferenceEquals, and Is. From my perspective, I also think that it is odd that with three alternatives, two of which are specifically created with the intention reference equality (one which exists in both VB and C#), that it is necessary to preserve Object's equals operator for checking reference equality.

I apologize if I confused things earlier when talking about pointers. C++ was the language I initially learned to program with so a lot of the metaphors I have to describe programming concepts are in terms of C++. I can see how it makes for a confusing conversation when metaphors don't align. For me, deep vs. shallow (i.e. value vs. reference) is something you always have to be aware of and continuously make conscience decisions about as you code. It's just the way I think about things and it make sense for me.

(And the take home message of the psycology article is that I only have a 50% chance of guessing your tone, marble_eater. 'Egocentrism' refers to the writer's assumption that the reader will understand the writer's tone and intention just by reading the text. I know you are being specific, but please be a little more careful about your tone when you're posting -- I can't see your body language.:) Some free advice -- "I Statements" go a long way to reducing friction and potential confrontation by allowing others to have options. I'm sure you've seen the matrix -- it's the same principle.)
 
If the VB "Is" operator is like C#'s "is", then that only compares types. Keep in mind that I'm a VB.NET noob :)

If I may summarize for those coming in late to the thread:
the topic of whether or not it's a good idea to overload Equals or == comes down to two opinions: when you see a comparison of two reference types, would you naturally assume you're comparing the references or the values. In easy terms: do the variables point to the exact same chunk-o-memory or do they both reference the same "value" such as Customer # 123.

I wouldn't presume to say that one is wrong versus the other as long as everyone on the team knows the standard. I would strongly suggest NOT mixing the two (some reference types compare by reference, some reference types compare by value) as you'll easily get confused.

I would be curious to see how each of you feel's about this subject in a year or so - if anyone has changed their mind. I wish there was a way to flag it to be "reopened" in a year :)

-ner
 
I created a quick and dirty program to test it out to make sure it all worked and the Is operator does indeed check for reference (that's why "someObj Is Nothing" is used instead of = nothing)
Visual Basic:
        Dim super As New ArrayList
        Dim duper As ArrayList = super
        Dim wicked As New ArrayList
        Dim awesome As ArrayList = wicked
        '
        super.Add(1)
        super.Add(2)
        duper.Add(3)
        MsgBox("super.cout = " + super.Count.ToString()) '3
        MsgBox("duper.cout = " + duper.Count.ToString()) '3
        MsgBox("is super the duper? " + (super Is duper).ToString()) 'true
        '
        wicked.Add(1)
        wicked.Add(2)
        awesome.Add(3)
        MsgBox("wicked.cout = " + wicked.Count.ToString()) '3
        MsgBox("awesome.cout = " + awesome.Count.ToString()) '3
        MsgBox("is wicked the awesome? " + (wicked Is awesome).ToString()) 'true
        '
        MsgBox("is wicked the super? " + (super Is wicked).ToString()) 'false
        MsgBox("is awesome the super? " + (super Is awesome).ToString()) 'false
        MsgBox("is wicked the duper? " + (duper Is wicked).ToString()) 'false
        MsgBox("is awesome the duper? " + (duper Is awesome).ToString()) 'false
So, in my opinion, at least in VB, I would say that use of the = operator to check whether two objects reference the same memory would be a bad practice becuase you have the Is operator, though I am unsure of the intention of the implementation of Object's = operator.

Now, in C#, things are a little different and it does make talking about .Net in general difficult becuase, at least as far as I know, there isn't anything like the Is operator for C#. At first I thought this was strange, but you can go into unsafe mode in C#, so maybe that's the reasoning behind it? I've never really done anything "unsafe" in C# before so I'm not really sure how deep it allows you to go.

I guess the bottom line, though, as Nerseus pointed out, so long as you are consistant and everyone you deal with understands you then there really isn't a wrong way to do it. So long as you are consistant and well documented, overload away -- there really isn't a convention or best practice (at least as far as I can tell).
 
Perhaps this is why our opinions on the subject are so different.

In VB there are two operators: Is and =. Forgetting overloading for the time being, = performs comparisons on elementary types and Is performs comparisons on object references (= can not compare references). In Visual Basic you have two distinct operators to perform two distinct functions: value comparison and reference comparison.

In C# there is only ==. == compares values. == compares references. In .Net 1.x, there was never an object that allowed for both value comparison and reference comparison, so it seemed to make sense to only have one equality operator. It was either an elementary type or an object, so which type of comparison we want to make is implied. In .Net 2.0, we introduce operator overloading, which allows value comparison in addition to reference comparison, and it can become difficult to tell which one the == operator is going to do.

So, Nerseus and I, primarily C# users, object to overloading == on reference types because it can confuse us, and you, a VB user, don't object because in the world of VB there is no ambiguity.

(Charts are fun)
Code:
Comparison of VB and C# operators

===================================
VB: = Operator
===================================
Type            Value     Reference
-----------------------------------
Elementary:     UnBoxed
Struct:       Overloaded
Class:        Overloaded

===================================
VB: Is Operator
===================================
Type            Value     Reference
-----------------------------------
Elementary:                 Boxed
Struct:                     Boxed
Class:                      Always



===================================
C#: == operator
===================================
Type            Value     Reference
-----------------------------------
Elementary:    UnBoxed     Boxed   (Must either be boxed or unboxed.)
Struct:      Overloaded    Boxed   (May be overloaded or boxed, but not both.)
Class:       Overloaded    Always, unless overloaded (our ambiguity)



So everyone is right. The only issue I can see with overloading = in VB is when the compiled code might be used by a C# coder.
 
One nitpicky point, operator overloading is only new to Visual Basic in .Net 2.0. It's been around in C# since the beginning.


marble_eater said:
The only issue I can see with overloading = in VB is when the compiled code might be used by a C# coder.
That is an interesting point. I wonder if there is a disparity similar to VB's parameters with default values? I'll have to do some more research to see how it all works. I do know that when you overloaded == in C# .Net 1.1, it (=) did not carry over to VB, but you were required to also overload the Equals method for objects (bool Equals(object)). In .Net 2.0, it seems like the overload carries over. So whatever was missing in 1.1 is in 2.0 now, though I'm unsure what it looks like at the IL level or even what the Is operator would look like, say in a method in reflector that you write in VB and observe in C#. I'm not really sure about the reverse because I usually do my library coding in C# and use it in VB winforms.

Now, the convention that we take when implementing a library in C# is to make == a deep equality operator, the bool Equals(object o) simply returns base.Equals(o) (object's Equals), and you also make an overload of bool Equals() which takes as an argument the type of the class you are creating and simply returns the results of the newly overloaded == operator (to play nice with VB). That's covered us pretty well and doesn't remove any functionality (though you can always cast to object if you have to use == for something that way -- which is what I usually do because I'm used to == for everything from my C++ days and forget about Equals methods). That is the convention that we use, though there may be a better way to go about things or a more widely accepted practice that we haven't figured out yet or don't know about.

I'm going to research the VB/C# thing a little but if anyone knows the answer or gets to it first, please post.
 
As far as the IL level, The VB Is and C# == (reference comparison) are the same: they load the operands' pointers on the stack and use the ceq (compare for equality) instruction. As a matter of fact, since value comparison and reference comparison both break down to the ceq instruction, it makes sense to use == for both. That is, until == is overloaded and can break down to either a function call or a ceq instruction.
 
marble_eater said:
That is, until == is overloaded and can break down to either a function call or a ceq instruction.
There has to be some way to remove the ambiguity or it wouldn't be possible to do the overload in the first place, right?
 
Technically, there is no ambiguity. If an overload exists, the function is called. If not, references are compared. But I am not a computer, and I can't remember every overload that exists. The ambiguity is the human factor, not a logical conflict. It comes into play when I go to see if two of my ListViewItem derived objects are the same object so that I may avoid referencing it twice in my ArrayList, but someone else overloaded the == operator to compare values instead of references so I remove the duplicate entries that I want instead of the duplicate references that I don't. The compiler knows what to do. The programmer is confused.
 
Sorry. I misunderstood what you were trying to say but I think I've got it now. The "ambiguity" is removed at compile time, because an ambiguity never existed in the first place. I was thinking inclusive or for some reason. No idea why, though.:)

I did some checking on a few things that were bugging me a little, such as the "irregular" equality operators on Strings not being due to operator overloading. It turns out that there isn't some kind of "compiler magic" going on for value types versus reference types that was alleged earlier. It actually is operator overloading that allows the string class to act like a value type instead of a reference type. Check it out in reflector:

C#:
public static bool Equals(string a, string b)
{
      if (a == b)  //this looks kind of funny, because it seems like a circular reference.  This is actually just reflector flipping out a little.  This is a reference check to make sure you aren't attempting to compare the same object before you go through a potentially lengthy character comparison.  Sadly, I am not sure of the actual code the developer used to make this check because it seems to of been scrubbed away in the translation process.
      {
            return true;  //this catches them both being null or same memory
      }
      if ((a != null) && (b != null))
      {
            return string.EqualsHelper(a, b); //this method does a character by character comparison just like looping through a char* by hand in C++
      }
      return false;
}

public static bool operator ==(string a, string b)
{
      return string.Equals(a, b);  //some good, DRY code.  Call the static equals method.  This is apparent in the IL with a call statement.
}

 //This is the real kicker that makes string a value type -- how the Equals(object) method is handled
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
public override bool Equals(object obj)
{
      string text1 = obj as string;  //first cast the object to a string
      if ((text1 == null) && (this != null))  //check your references to make sure you can do a value check without throwing a silly exception that doesn't make sense, though the this check for null doesn't really make sense.
      {
            return false;
      }
      return string.EqualsHelper(this, text1); //it actually does a value check here
}

Because reflector sometimes messes the reverse engineering up because a statement can sometimes be interpreted several ways, it is helpful to look at things through different views to make sure you get the full meaning. I am fairly confident the IL will give the definitive solution (duh, because that's what the assembly is in when reflector gets it...:) ) but I can't read IL very well so for the purposes of this conversation, we'll look at VB.

Visual Basic:
Public Shared Function Equals(ByVal a As String, ByVal b As String) As Boolean
      If (a Is b) Then  ''as you can see it is a simple reference check
            Return True
      End If
      If ((Not a Is Nothing) AndAlso (Not b Is Nothing)) Then  ''same thing here to prevent a null reference exception before the big comparison
            Return String.EqualsHelper(a, b)
      End If
      Return False
End Function
So, in summary, the String Class is considered a value type because it was instructed to act like a value type, not because there is something special going on behind the scenes. This is great news because it means everything is internally consistent and that there isn't some kind of magical hand waving that goes on for value vs reference classes. It also means that you too can create your very own value types -- it's as simple as overloading a few operators/methods the correct way.

The one thing that is still kind of confusing then is, how does this all come together if everything is really a reference type and value types are just implemented operators in a special way? Deep down inside there actually primitives that are so abstracted away from us that we never have to worry about them (unless you want to), and as far as we are concerned, they don't exist. What really makes string a value type more than anything else is the actual check for equality that is done in the EqualsHelper() method.
C#:
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
private static unsafe bool EqualsHelper(string strA, string strB)
{
      int num1 = strA.Length;
      if (num1 != strB.Length)
      {
            return false;
      }
      fixed (char* text1 = ((char*) strA))
      {
            char* chPtr1 = text1;
            fixed (char* text2 = ((char*) strB))
            {
                  char* chPtr2 = text2;
                  char* chPtr3 = chPtr1;
                  char* chPtr4 = chPtr2;
                  while (num1 >= 10)
                  {
                        if ((((*(((int*) chPtr3)) != *(((int*) chPtr4))) || (*(((int*) (chPtr3 + 2))) != *(((int*) (chPtr4 + 2))))) || ((*(((int*) (chPtr3 + 4))) != *(((int*) (chPtr4 + 4)))) || (*(((int*) (chPtr3 + 6))) != *(((int*) (chPtr4 + 6)))))) || (*(((int*) (chPtr3 + 8))) != *(((int*) (chPtr4 + 8)))))
                        {
                              break;
                        }
                        chPtr3 += 10;
                        chPtr4 += 10;
                        num1 -= 10;
                  }
                  while (num1 > 0)
                  {
                        if (*(((int*) chPtr3)) != *(((int*) chPtr4)))
                        {
                              break;
                        }
                        chPtr3 += 2;
                        chPtr4 += 2;
                        num1 -= 2;
                  }
                  return (num1 <= 0);
            }
      }
}

Boom. Unsafe code, just as I would have expected there to be in the deep dark catacombs of .Net, the beams that hold the whole thing together. Here, you actually have access to the pointer and the thing it points to. This method effectively makes String a value type. It's not a value type because there's anything magical going on or it is just special, it's a value type because it was designed to be that way.

I did exaggerate slightly above with regards to making your own value type. There is something that makes the string class special in that when you call string equality in your own methods, the ceq is invoked in the IL, where as it is not when I write my own equality operators (even though those operators eventually check value based on value types such as strings and ints. Maybe it's the serializable attribute? Maybe there is something else? And then again, maybe there really is some kind of additional magic going on behind the scenes for Strings as every other value type I was able to find with this equals style implementation was a struct. (Maybe I should spawn a new thread about the string equals? Unless I missed something, it does seem kind of strange?)

So, the bottom line here is that as long as you are actively deciding why you implement something in a certain way and make sure that it is well documented, then it is perfectly legit to overload == or not -- it all depends on your wants and needs. If it's ok with you, I'd like to officially consider the operator equals overload matter closed and just agree to disagree. We can chalk it up to differences in style as it seems neither way is really incorrect or wrong.:)

> /handshake marble_eater
> mskeel extends his hand in friendship to marble_eater
 
In VB7, there was no operator overloading. = Did not call the Equals method, even when overridden, yet you could use = on strings to test for equal value. In VB7, = is translated internally as a VB string comparison function (which happens to use String.Equals), hence, my irregular behavior for a "Magic" type. In .Net 2, the string class actually has operator overloads.

Perhaps on a simple class which more represents a value than an object (for instance, a string), operator overloads may be appropriate, provided that the people using the code are aware. I'm just worried about the guy who downloads sample code or a .dll to use, misses the line where you mention that == is overridden, and pulls his hair out trying to figure out why his program is broken. I just code with the convention that overloading == is bad. But, hey, what it always come down to is do what works for you.
 
marble_eater said:
In VB7, there was no operator overloading.
100% true. In my in-depth analysis of the quirky-ness of the String Class I forgot to look at .Net 1.1 (ayee!). I think everything makes sense for me now and I can see why overloading equals was just crazy in that context. I wish I would have had this conversation a few years ago when I firt picked up .Net. Meanwhile, .Net 2.0 brought VB and C# a little closer together, so a lot of these oddities were resolved. Regardless, String still seems to be the outlier.

I'm sorry I was such a pain in the neck for a while there, but I think it was a great discussion. Thanks, guys.
 
Back
Top