Note: This article assumes that you have read all previous “Beginner” articles, and you know how to create an instance of a class.

Introduction

Operator Overloading is a feature of C# that acts as syntactic sugar in the code, and eases the use of libraries in your programs. Because this feature is not present in Java, operator overloading makes C# appealing to many programmers including myself. With this feature, you can create your own user-defined implementations of operators (such as > and <) for your own user-defined classes and structs. This feature is particularly useful for creation of libraries, as it will not only help you, but it will help others that use your library in the future.

In this article, I will teach you the use cases of Operator Overloading, when not to use it, and how to best implement it in C#.

Which operators can be overloaded?

MSDN provides a complete list of operators that can be overloaded. In short, unary operators (as in the + of i++), binary operators (as in the + of obj1 + obj2), comparison operators (as in > and <), and conversion operators can be overloaded.

Use Cases

Suppose you have a class called Vector3f for storing three floats (x, y and z). These three floats correspond to mathematical vectors used for operations on three-dimensional vectors (this is commonly found in graphics libraries). We would traditionally need separate methods to operate on them: a method to add vector values, one to subtract them, one to multiply them, etc. Such an implementation would look like this:

We would then use this class in our program, and operate on the objects, as follows:

However, this code seems awfully redundant and hard to maintain. Wouldn’t it be neat if you could simply perform operations on the objects directly, such as vec1 + vec2?

Defining Overloads – In Practice

Operator-overloading reduces the need to explicitly call methods for such trivial tasks. If you were using Java, you would have stick with implementing methods for each operation of the vectors, since Java does not support operator-overloading. In C#, fortunately, we can use operator-overloading to implement syntactic sugar for trivial tasks like vec1 + vec2 as follows:

From here on, we simply use the operators in our program as follows:

Any operator that can be overloaded gets overloaded in the following way:

So, if you want to implement equality (==) and inequality (!=), you can do so as follows:

Similarly, if you wanted to overload the increment (++) and decrement (–) operators, you would do so as follows:

Now, these overloaded operators can be used on the objects as follows:

When NOT to use Operator Overloading

Because it eases the use of libraries, some people (just for the sake of shrinking the code base) use operator-overloading in places where there’s a chance of an ambiguity. You should only overload operators on logical types where its meaning is obvious. Consider this class for holding an array:

In this case, we overloaded the + operator, so that we can add any integer to all of the array’s members. The problem is that a programmer wouldn’t know which number (in the array) is being added to. Since there is no addition through indexing, it is pretty ambiguous whether the variable being added is simply an integer or an array of integers.

A simple way to make your code less ambiguous is to provide the equivalent methods for overloaded-operators. For example, if a user of your library can’t understand operators that you have overloaded, then she or he could just use the methods (and achieve the desired results).

You should also overload in a symmetric manner. For instance, if you are overloading + and -, then it also makes sense to overload * and /. Similarly, if you are overloading equality (==) then you should overload inequality (!=) too.

Overall, I think that operator-overloading is a really useful feature… if used properly where it makes sense. It’s a good idea to use it on things like logical numbers, vector-like structures (quaternions, matrices), etc. In short, it should be used in places where the resulting effects would be obvious.

Will you be willing to use this feature in your library? Or would you just prefer to use methods for the sake of consistency with your Java code? What are your thoughts?

 

Share

Comments are closed.

Post Navigation