Some programming languages allow a type to define how operators should manipulate instances of the type. For example, a lot of types (such as System.String, System.Decimal, and System.Date Time) overload the equality (==) and inequality (!=) operators. The CLR doesn’t know anything about operator overloading because it doesn’t even know what an operator is. Your programming language defines what each operator symbol means and what code should be generated when these special symbols appear.
For example, in C#, applying the + symbol to primitive numbers causes the compiler to generate code that adds the two numbers together. When the + symbol is applied to String objects, the C# compiler generates code that concatenates the two strings together. For inequality, C# uses the != symbol, while Microsoft Visual Basic uses the <> symbol. Finally, the ^ symbol means exclusive OR (XOR) in C#, but it means exponent in Visual Basic.
Although the CLR doesn’t know anything about operators, it does specify how languages should expose operator overloads so that they can be readily consumed by code written in a different programming language. Each programming language gets to decide for itself whether it will sup- port operator overloads, and if it does, the syntax for expressing and using them. As far as the CLR is concerned, operator overloads are simply methods.
Your choice of programming language determines whether or not you get the support of opera- tor overloading and what the syntax looks like. When you compile your source code, the compiler produces a method that identifies the behavior of the operator. The CLR specification mandates that operator overload methods be public and static methods. In addition, C# (and many other lan- guages) requires that at least one of the operator method’s parameters must be the same as the type
that the operator method is defined within. The reason for this restriction is that it enables the C#
compiler to search for a possible operator method to bind to in a reasonable amount of time.
Here is an example of an operator overload method defined in a C# class definition.
public sealed class Complex {
public static Complex operator+(Complex c1, Complex c2) { ... }
}
The compiler emits a metadata method definition entry for a method called op_Addition; the method definition entry also has the specialname flag set, indicating that this is a “special” method. When language compilers (including the C# compiler) see a + operator specified in source code, they look to see if one of the operand’s types defines a specialname method called op_Addition whose parameters are compatible with the operand’s types. If this method exists, the compiler emits code to call this method. If no such method exists, a compilation error occurs.
Tables 8-1 and 8-2 show the set of unary and binary operators that C# supports being overloaded, their symbols, and the corresponding Common Language Specification (CLS) method name that the compiler emits. I’ll explain the tables’ third columns in the next section.
TABLE 8-1C# Unary Operators and Their CLS-Compliant Method Names
C# Operator Symbol
Special Method Name
Suggested CLS-Compliant Method Name
+
op_UnaryPlus
Plus
op_UnaryNegation
Negate
!
op_LogicalNot
Not
~
op_OnesComplement
OnesComplement
++
op_Increment
Increment
op_Decrement
Decrement
(none)
op_True
IsTrue { get; }
(none)
op_False
IsFalse { get; }
TABLE 8-2C# Binary Operators and Their CLS-Compliant Method Names
C# Operator Symbol
Special Method Name
Suggested CLS-Compliant Method Name
+
op_Addition
Add
op_Subtraction
Subtract
*
op_Multiply
Multiply
/
op_Division
Divide
%
op_Modulus
Mod
&
op_BitwiseAnd
BitwiseAnd
|
op_BitwiseOr
BitwiseOr
^
op_ExclusiveOr
Xor
C# Operator Symbol
Special Method Name
Suggested CLS-Compliant Method Name
<<
op_LeftShift
LeftShift
>>
op_RightShift
RightShift
==
op_Equality
Equals
!=
op_Inequality
Equals
<
op_LessThan
Compare
>
op_GreaterThan
Compare
<=
op_LessThanOrEqual
Compare
>=
op_GreaterThanOrEqual
Compare
The CLR specification defines many additional operators that can be overloaded, but C# does not support these additional operators. Therefore, they are not in mainstream use, so I will not list them here. If you are interested in the complete list, please see the ECMA specifications (www.ecma-international.org/publications/standards/Ecma-335.htm) for the Common Language Infrastructure (CLI), Partition I, Concepts and Architecture, Sections 10.3.1 (unary operators) and
10.3.2 (binary operators).
Operators and Programming Language Interoperability
Operator overloading can be a very useful tool, allowing developers to express their thoughts with succinct code. However, not all programming languages support operator overloading. When using a language that doesn’t support operator overloading, the language will not know how to interpret the
+ operator (unless the type is a primitive in that language), and the compiler will emit an error. When using languages that do not support operator overloading, the language should allow you to call the desired op_* method directly (such as op_Addition).
If you are using a language that doesn’t support + operator overloading to be defined in a type,
obviously, this type could still offer an op_Addition method. From C#, you might expect that you
could call this op_Addition method by using the + operator, but you cannot. When the C# compiler detects the + operator, it looks for an op_Addition method that has the specialname metadata flag associated with it so that the compiler knows for sure that the op_Addition method is intended to be an operator overload method. Because the op_Addition method is produced by a language that doesn’t support operator overloads, the method won’t have the specialname flag associated with it, and the C# compiler will produce a compilation error. Of course, code in any language can ex- plicitly call a method that just happens to be named op_Addition, but the compilers won’t translate a usage of the + symbol to call this method.
Jeff’s Opinion About Microsoft’s Operator Method Name Rules
I’m sure that all of these rules about when you can and can’t call an operator overload method seem very confusing and overly complicated. If compilers that supported operator overloading just didn’t emit the specialname metadata flag, the rules would be a lot simpler, and pro- grammers would have an easier time working with types that offer operator overload methods. Languages that support operator overloading would support the operator symbol syntax, and all languages would support calling the various op_ methods explicitly. I can’t come up with any reason why Microsoft made this so difficult, and I hope that they’ll loosen these rules in future versions of their compilers.
For a type that defines operator overload methods, Microsoft recommends that the type also define friendlier public static methods that call the operator overload methods internally. For example, a public-friendly named method called Add should be defined by a type that over- loads the op_Addition method. The third column in Tables 8-1 and 8-2 lists the recommended friendly name for each operator. So the Complex type shown earlier should be defined in the following way.
public sealed class Complex {
public static Complex operator+(Complex c1, Complex c2) { ... }
Certainly, code written in any programming language can call any of the friendly operator methods, such as Add. Microsoft’s guideline that types offer these friendly method names com- plicates the story even more. I feel that this additional complication is unnecessary, and that calling these friendly named methods would cause an additional performance hit unless the JIT compiler is able to inline the code in the friendly named method. Inlining the code would cause the JIT compiler to optimize the code, removing the additional method call and boosting run- time performance.