Overloading binary operators in D
Operator overloading in object-oriented programming
Operator overloading is a type of compile-time polymorphism. In this process, the compiler determines which function to execute from a group of functions with the same name based on the types of parameters involved.
In D language, we can overload binary operators by defining special methods within our custom type.
The method name corresponds to the overloaded operator. By overloading binary operators, we can make the operators behave for our defined struct as per our requirements.
The opBinary and opCmp methods
The opBinary method is a generic function that takes a string op representing the operator and is used to overload binary operators like +, -, *, = etc. In the opBinary method, the condition if (op == "...") is used to specify which operator is being overloaded. While opCmp is used to overload comparison operators like <, <=, ==, !=, >=, >. This method generally returns 0 for equality, a negative value for less than, and a positive value for greater than.
Binary operators are broadly divided into four categories:
Arithmetic operators
Assignment operators
Bitwise operators
Relational operators
Following are the code examples for each type of binary operator.
Example 1: Overloading the arithmetic operator
import std.stdio;struct Vector {int x, y;// Overloading the + operatorVector opBinary(string op)(Vector other) if (op == "+") {return Vector(x + other.x, y + other.y);}}void main() {Vector v1 = Vector(1, 2);Vector v2 = Vector(3, 4);Vector v3 = v1 + v2;// Now v3.x will be 1 + 3 = 4, v3.y will be 2 + 4 = 6writeln("(", v3.x, ", ", v3.y, ")");}
Explanation:
Line 1: A package for input-output operations is imported.
Line 2: A struct
Vectoris defined as having two member variables.Lines 5–7: The
+operator is overloaded using theopBinarymethod. This function takes anotherVectoras an argument and returns a newVectorwith the added components.Lines 11–12: Two
Vectorobjects are declared and initialized.Line 13: Another
Vectorobject is declared that is initialized using the overloaded+operator.Line 15: The output is displayed.
Example 2: Overloading the assignment operator
import std.stdio;struct Vector {int x, y;// Overloading the assignment operatorvoid opBinary(string op)(string newValue) if (op == "=") {value = newValue;}}void main() {Vector v1 = Vector(1, 9);Vector v2 = v1;writeln("(", v2.x, ", ", v2.y, ")");}
Explanation:
Line 1: A package for input-output operations is imported.
Line 2: A struct
Vectoris defined as having two member variables.Lines 5–7: The
=operator is overloaded using theopBinarymethod. This function takes anotherVectoras an argument and returns the result of comparison.Line 11: A
Vectorobject is declared and initialized.Line 12: Another
Vectorobject is declared and initialized with the overloaded assignment operator.Line 13: The result of the assignment is displayed.
Example 3: Overloading bitwise operator
import std.stdio;struct Bitwise {int bits;Bitwise opBinary(string op)(Bitwise other) if (op == "&") {return Bitwise(bits & other.bits);}}void main() {Bitwise b1 = Bitwise(5); // 5 in integer = 0101 in binaryBitwise b2 = Bitwise(3); // 3 in integer = 0011 in binaryBitwise result = b1 & b2; // 0001 in binary = 1 in integerwriteln("Result: ", result.bits);}
Explanation:
Line 1: A package for input-output operations is imported.
Line 2: A struct
Bitwiseis defined as having an integer member variable.Lines 4–6: The
&operator is overloaded using theopBinarymethod. This function takes anotherBitwiseobject as an argument and returns the result of bitwiseand.Lines 10–11: Two
Bitwiseobjects are declared and initialized.Line 12: The overloaded relational operator
&is called, and the result is stored in anotherBitwiseobject.Line 13: The result of the bitwise
andis displayed.
Example 4: Overloading the relational operator
import std.stdio;struct Vector {int x, y;// Overloading the relational operator ">"int opCmp(Vector other) {if (x == other.x && y == other.y) return 0;return (x > other.x && y > other.y) ? 1 : -1;}}void main() {Vector v1 = Vector(1, 2);Vector v2 = Vector(3, 4);bool result = v1 > v2;writeln("Result: ", result);}
Explanation:
Line 1: A package for input-output operations is imported.
Line 2: A struct
Vectoris defined as having two member variables.Lines 5–8: The
>operator is overloaded using theopCmpmethod. This function takes anotherVectoras an argument and returns the result of comparison.Lines 12–13: Two
Vectorobjects are declared and initialized.Line 14: The overloaded relational operator
>is called, and the result is stored in a variable.Line 15: The result of the comparison is displayed.
In summary, overloading binary operators in D enhances code expressiveness and flexibility, enabling developers to create more intuitive and readable programs. This feature, demonstrated in this answer in terms of syntax and importance, provides an amazing tool for achieving polymorphism and adhering to object-oriented programming principles in the D language.
Free Resources